diff --git a/.gitattributes b/.gitattributes
index 7015991dd6..e0b6b87c6b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -8136,18 +8136,26 @@ utils/fppkg/fppkg.pp svneol=native#text/plain
utils/fppkg/fprepos.pp svneol=native#text/plain
utils/fppkg/fpxmlrep.pp svneol=native#text/plain
utils/fppkg/lnet/LICENSE -text
+utils/fppkg/lnet/LICENSE.ADDON -text
utils/fppkg/lnet/fastcgi.pp svneol=native#text/plain
utils/fppkg/lnet/lcommon.pp svneol=native#text/plain
utils/fppkg/lnet/lcontainers.inc svneol=native#text/plain
utils/fppkg/lnet/lcontainersh.inc svneol=native#text/plain
utils/fppkg/lnet/lcontrolstack.pp svneol=native#text/plain
utils/fppkg/lnet/levents.pp svneol=native#text/plain
+utils/fppkg/lnet/lfastcgi.pp svneol=native#text/plain
utils/fppkg/lnet/lftp.pp svneol=native#text/plain
+utils/fppkg/lnet/lhttp.pp svneol=native#text/plain
+utils/fppkg/lnet/lhttputil.pp svneol=native#text/plain
+utils/fppkg/lnet/lmimetypes.pp svneol=native#text/plain
utils/fppkg/lnet/lnet.pp svneol=native#text/plain
+utils/fppkg/lnet/lprocess.pp svneol=native#text/plain
+utils/fppkg/lnet/lsmtp.pp svneol=native#text/plain
+utils/fppkg/lnet/lspawnfcgi.pp svneol=native#text/plain
utils/fppkg/lnet/lstrbuffer.pp svneol=native#text/plain
utils/fppkg/lnet/ltelnet.pp svneol=native#text/plain
+utils/fppkg/lnet/ltimer.pp svneol=native#text/plain
utils/fppkg/lnet/lwebserver.pp svneol=native#text/plain
-utils/fppkg/lnet/openssl.pp -text svneol=unset#text/plain
utils/fppkg/lnet/sys/lepolleventer.inc svneol=native#text/plain
utils/fppkg/lnet/sys/lepolleventerh.inc svneol=native#text/plain
utils/fppkg/lnet/sys/lkqueueeventer.inc svneol=native#text/plain
diff --git a/utils/fppkg/lnet/LICENSE.ADDON b/utils/fppkg/lnet/LICENSE.ADDON
new file mode 100644
index 0000000000..f134b1e33d
--- /dev/null
+++ b/utils/fppkg/lnet/LICENSE.ADDON
@@ -0,0 +1,19 @@
+This is the file LICENSE.Addon, it applies to the Lighweight Network Library (lnet).
+
+The source code of the Lightweight Network library are
+distributed under the Library GNU General Public License
+(see the file LICENSE) with the following modification:
+
+- object files and libraries linked into an application may be
+ distributed without source code.
+
+The unit tomwinsock.pas is EXLUDED from both the GPL and this addon license.
+It is distributed under the terms of BSD license as mentioned in the file.
+I am NOT the author of tomwinsock.pas
+
+If you didn't receive a copy of the file LICENSE, contact:
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330
+ Boston, MA 02111
+ USA
+
diff --git a/utils/fppkg/lnet/levents.pp b/utils/fppkg/lnet/levents.pp
index bffb5a43eb..cf0c3c734e 100644
--- a/utils/fppkg/lnet/levents.pp
+++ b/utils/fppkg/lnet/levents.pp
@@ -317,7 +317,7 @@ function TLEventer.Bail(const msg: string; const Ernum: Integer): Boolean;
begin
Result := False; // always false, substitute for caller's result
if Assigned(FOnError) then
- FOnError(msg + ': ' + LStrError(Ernum), Self);
+ FOnError(msg + '[' + IntToStr(Ernum) + ']: ' + LStrError(Ernum), Self);
end;
procedure TLEventer.AddForFree(aHandle: TLHandle);
diff --git a/utils/fppkg/lnet/lfastcgi.pp b/utils/fppkg/lnet/lfastcgi.pp
new file mode 100644
index 0000000000..2a8320c92a
--- /dev/null
+++ b/utils/fppkg/lnet/lfastcgi.pp
@@ -0,0 +1,910 @@
+{ FastCGI requester support for lNet
+
+ Copyright (C) 2006 Micha Nelissen
+
+ This library is Free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is diStributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+ for more details.
+
+ You should have received a Copy of the GNU Library General Public License
+ along with This library; if not, Write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ This license has been modified. See file LICENSE.ADDON for more information.
+ Should you find these sources without a LICENSE File, please contact
+ me at ales@chello.sk
+}
+
+unit lfastcgi;
+
+{$mode objfpc}{$h+}
+
+interface
+
+uses
+ classes, sysutils, fastcgi, lnet, levents, lstrbuffer, ltimer;
+
+type
+ TLFastCGIClient = class;
+ TLFastCGIRequest = class;
+ TLFastCGIPool = class;
+
+ TLFastCGIRequestEvent = procedure(ARequest: TLFastCGIRequest) of object;
+
+ PLFastCGIRequest = ^TLFastCGIRequest;
+ TLFastCGIRequest = class(TObject)
+ protected
+ FID: integer;
+ FClient: TLFastCGIClient;
+ FBuffer: TStringBuffer;
+ FBufferSendPos: integer;
+ FHeader: FCGI_Header;
+ FHeaderPos: integer;
+ FContentLength: integer;
+ FInputBuffer: pchar;
+ FInputSize: integer;
+ FOutputDone: boolean;
+ FStderrDone: boolean;
+ FOutputPending: boolean;
+ FNextFree: TLFastCGIRequest;
+ FNextSend: TLFastCGIRequest;
+ FOnEndRequest: TLFastCGIRequestEvent;
+ FOnInput: TLFastCGIRequestEvent;
+ FOnOutput: TLFastCGIRequestEvent;
+ FOnStderr: TLFastCGIRequestEvent;
+
+ procedure HandleReceive;
+ procedure HandleReceiveEnd;
+ function HandleSend: boolean;
+ procedure DoEndRequest;
+ procedure DoOutput;
+ procedure DoStderr;
+ procedure EndRequest;
+ procedure RewindBuffer;
+ procedure SetContentLength(NewLength: integer);
+ procedure SendEmptyRec(AType: integer);
+ procedure SendGetValues;
+ procedure SetID(const NewID: integer);
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ procedure AbortRequest;
+ function Get(ABuffer: pchar; ASize: integer): integer;
+ procedure ParseClientBuffer;
+ function SendBuffer: integer;
+ function SendPrivateBuffer: boolean;
+ procedure SendBeginRequest(AType: integer);
+ procedure SendParam(const AName, AValue: string; AReqType: integer = FCGI_PARAMS);
+ function SendInput(const ABuffer: pchar; ASize: integer): integer;
+ procedure DoneParams;
+ procedure DoneInput;
+
+ property ID: integer read FID write SetID;
+ property StderrDone: boolean read FStderrDone;
+ property OutputDone: boolean read FOutputDone;
+ property OutputPending: boolean read FOutputPending;
+ property OnEndRequest: TLFastCGIRequestEvent read FOnEndRequest write FOnEndRequest;
+ property OnInput: TLFastCGIRequestEvent read FOnInput write FOnInput;
+ property OnOutput: TLFastCGIRequestEvent read FOnOutput write FOnOutput;
+ property OnStderr: TLFastCGIRequestEvent read FOnStderr write FOnStderr;
+ end;
+
+ TFastCGIClientState = (fsIdle, fsConnecting, fsConnectingAgain,
+ fsStartingServer, fsHeader, fsData, fsFlush);
+
+ PLFastCGIClient = ^TLFastCGIClient;
+ TLFastCGIClient = class(TLTcp)
+ protected
+ FRequests: PLFastCGIRequest;
+ FRequestsCount: integer;
+ FNextRequestID: integer;
+ FRequestsSent: integer;
+ FFreeRequest: TLFastCGIRequest;
+ FSendRequest: TLFastCGIRequest;
+ FRequest: TLFastCGIRequest;
+ FState: TFastCGIClientState;
+ FNextFree: TLFastCGIClient;
+ FPool: TLFastCGIPool;
+ FBuffer: pchar;
+ FBufferEnd: pchar;
+ FBufferPos: pchar;
+ FBufferSize: dword;
+ FReqType: byte;
+ FContentLength: integer;
+ FPaddingLength: integer;
+
+ function Connect: Boolean; override;
+ procedure ConnectEvent(ASocket: TLHandle); override;
+ procedure DisconnectEvent(ASocket: TLHandle); override;
+ procedure ErrorEvent(const Msg: string; ASocket: TLHandle); override;
+ function CreateRequester: TLFastCGIRequest;
+ procedure HandleGetValuesResult;
+ procedure HandleReceive(ASocket: TLSocket);
+ procedure HandleSend(ASocket: TLSocket);
+ procedure ParseBuffer;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+
+ procedure AddToSendQueue(ARequest: TLFastCGIRequest);
+ function BeginRequest(AType: integer): TLFastCGIRequest;
+ procedure EndRequest(ARequest: TLFastCGIRequest);
+ procedure Flush;
+ function GetBuffer(ABuffer: pchar; ASize: integer): integer;
+
+ property ReqType: byte read FReqType;
+ property RequestsSent: integer read FRequestsSent;
+ end;
+
+ TSpawnState = (ssNone, ssSpawning, ssSpawned);
+
+ TLFastCGIPool = class(TObject)
+ protected
+ FClients: PLFastCGIClient;
+ FClientsCount: integer;
+ FClientsAvail: integer;
+ FClientsMax: integer;
+ FMaxRequestsConn: integer;
+ FFreeClient: TLFastCGIClient;
+ FTimer: TLTimer;
+ FEventer: TLEventer;
+ FAppName: string;
+ FAppEnv: string;
+ FHost: string;
+ FPort: integer;
+ FSpawnState: TSpawnState;
+
+ procedure AddToFreeClients(AClient: TLFastCGIClient);
+ function CreateClient: TLFastCGIClient;
+ procedure ConnectClients(Sender: TObject);
+ procedure StartServer;
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ function BeginRequest(AType: integer): TLFastCGIRequest;
+ procedure EndRequest(AClient: TLFastCGIClient);
+
+ property AppEnv: string read FAppEnv write FAppEnv;
+ property AppName: string read FAppName write FAppName;
+ property ClientsMax: integer read FClientsMax write FClientsMax;
+ property Eventer: TLEventer read FEventer write FEventer;
+ property MaxRequestsConn: integer read FMaxRequestsConn write FMaxRequestsConn;
+ property Host: string read FHost write FHost;
+ property Port: integer read FPort write FPort;
+ property Timer: TLTimer read FTimer;
+ end;
+
+implementation
+
+uses
+ lSpawnFCGI;
+
+{ TLFastCGIRequest }
+
+constructor TLFastCGIRequest.Create;
+begin
+ inherited;
+
+ FBuffer := InitStringBuffer(504);
+ FHeader.Version := FCGI_VERSION_1;
+ FHeaderPos := -1;
+end;
+
+destructor TLFastCGIRequest.Destroy;
+begin
+ inherited;
+ FreeMem(FBuffer.Memory);
+end;
+
+procedure TLFastCGIRequest.HandleReceive;
+begin
+ case FClient.ReqType of
+ FCGI_STDOUT: DoOutput;
+ FCGI_STDERR: DoStderr;
+ FCGI_END_REQUEST: EndRequest;
+ FCGI_GET_VALUES_RESULT: FClient.HandleGetValuesResult;
+ else
+ FClient.Flush;
+ end;
+end;
+
+procedure TLFastCGIRequest.HandleReceiveEnd;
+begin
+ case FClient.ReqType of
+ FCGI_STDOUT: FOutputDone := true;
+ FCGI_STDERR: FStderrDone := true;
+ end;
+end;
+
+function TLFastCGIRequest.HandleSend: boolean;
+begin
+ if FOnInput <> nil then
+ FOnInput(Self);
+ Result := FInputBuffer = nil;
+end;
+
+procedure TLFastCGIRequest.DoOutput;
+begin
+ if FOnOutput <> nil then
+ FOnOutput(Self);
+end;
+
+procedure TLFastCGIRequest.DoStderr;
+begin
+ if FOnStderr <> nil then
+ FOnStderr(Self);
+end;
+
+procedure TLFastCGIRequest.DoEndRequest;
+begin
+ if FOnEndRequest <> nil then
+ FOnEndRequest(Self);
+end;
+
+procedure TLFastCGIRequest.EndRequest;
+begin
+ FOutputDone := false;
+ FStderrDone := false;
+ FClient.EndRequest(Self);
+ FClient.Flush;
+ RewindBuffer;
+ DoEndRequest;
+end;
+
+function TLFastCGIRequest.Get(ABuffer: pchar; ASize: integer): integer;
+begin
+ Result := FClient.GetBuffer(ABuffer, ASize);
+end;
+
+procedure TLFastCGIRequest.ParseClientBuffer;
+begin
+ FOutputPending := false;
+ if (FClient.Iterator <> nil) and FClient.Iterator.IgnoreRead then
+ FClient.HandleReceive(nil)
+ else
+ FClient.ParseBuffer;
+end;
+
+procedure TLFastCGIRequest.SetID(const NewID: integer);
+begin
+ FID := NewID;
+ FHeader.RequestIDB0 := byte(NewID and $FF);
+ FHeader.RequestIDB1 := byte((NewID shr 8) and $FF);
+end;
+
+procedure TLFastCGIRequest.SetContentLength(NewLength: integer);
+begin
+ FContentLength := NewLength;
+ FHeader.ContentLengthB0 := byte(NewLength and $FF);
+ FHeader.ContentLengthB1 := byte((NewLength shr 8) and $FF);
+ FHeader.PaddingLength := byte(7-((NewLength+7) and 7));
+end;
+
+const
+ PaddingBuffer: array[0..7] of char = (#0, #0, #0, #0, #0, #0, #0, #0);
+type
+ TLFastCGIStringSize = record
+ Size: integer;
+ SizeBuf: array[0..3] of char;
+ end;
+
+function GetFastCGIStringSize(ABufferPos: pbyte; var ASize: integer): integer;
+begin
+ ASize := ABufferPos[0];
+ if ASize >= 128 then
+ begin
+ ASize := ((ABufferPos[0] shl 24) and $7f) or (ABufferPos[1] shl 16)
+ or (ABufferPos[2] shl 8) or ABufferPos[3];
+ Result := 4;
+ end else
+ Result := 1;
+end;
+
+procedure FillFastCGIStringSize(const AStr: string; var AFastCGIStr: TLFastCGIStringSize);
+var
+ lLen: dword;
+begin
+ lLen := dword(Length(AStr));
+ if lLen > 127 then
+ begin
+ AFastCGIStr.Size := 4;
+ AFastCGIStr.SizeBuf[0] := char($80 + ((lLen shr 24) and $ff));
+ AFastCGIStr.SizeBuf[1] := char((lLen shr 16) and $ff);
+ AFastCGIStr.SizeBuf[2] := char((lLen shr 8) and $ff);
+ AFastCGIStr.SizeBuf[3] := char(lLen and $ff);
+ end else begin
+ AFastCGIStr.Size := 1;
+ AFastCGIStr.SizeBuf[0] := char(lLen);
+ end;
+end;
+
+procedure TLFastCGIRequest.SendBeginRequest(AType: integer);
+var
+ lBody: FCGI_BeginRequestBody;
+begin
+ lBody.roleB1 := byte((AType shr 8) and $ff);
+ lBody.roleB0 := byte(AType and $ff);
+ lBody.flags := FCGI_KEEP_CONN;
+ FHeader.ReqType := FCGI_BEGIN_REQUEST;
+ SetContentLength(sizeof(lBody));
+ AppendString(FBuffer, @FHeader, sizeof(FHeader));
+ AppendString(FBuffer, @lBody, sizeof(lBody));
+end;
+
+procedure TLFastCGIRequest.SendParam(const AName, AValue: string; AReqType: integer = FCGI_PARAMS);
+var
+ lNameLen: TLFastCGIStringSize;
+ lValueLen: TLFastCGIStringSize;
+ lTotalLen: integer;
+begin
+ FillFastCGIStringSize(AName, lNameLen);
+ FillFastCGIStringSize(AValue, lValueLen);
+ lTotalLen := lNameLen.Size+lValueLen.Size+Length(AName)+Length(AValue);
+ if (FHeader.ReqType = AReqType) and (FBufferSendPos = 0)
+ and (0 <= FHeaderPos) and (FHeaderPos < FBuffer.Pos - FBuffer.Memory) then
+ begin
+ { undo padding }
+ Dec(FBuffer.Pos, FHeader.PaddingLength);
+ SetContentLength(FContentLength+lTotalLen);
+ Move(FHeader, FBuffer.Memory[FHeaderPos], sizeof(FHeader));
+ end else begin
+ FHeader.ReqType := AReqType;
+ SetContentLength(lTotalLen);
+ FHeaderPos := FBuffer.Pos - FBuffer.Memory;
+ AppendString(FBuffer, @FHeader, sizeof(FHeader));
+ end;
+ AppendString(FBuffer, @lNameLen.SizeBuf[0], lNameLen.Size);
+ AppendString(FBuffer, @lValueLen.SizeBuf[0], lValueLen.Size);
+ AppendString(FBuffer, AName);
+ AppendString(FBuffer, AValue);
+ AppendString(FBuffer, @PaddingBuffer[0], FHeader.PaddingLength);
+end;
+
+procedure TLFastCGIRequest.SendGetValues;
+var
+ lRequestID: integer;
+begin
+ { management record type has request id 0 }
+ lRequestID := ID;
+ ID := 0;
+ SendParam('FCGI_MAX_REQS', '', FCGI_GET_VALUES);
+ { if we're the first connection, ask max. # connections }
+ if FClient.FPool.FClientsAvail = 1 then
+ SendParam('FCGI_MAX_CONNS', '', FCGI_GET_VALUES);
+ ID := lRequestID;
+end;
+
+function TLFastCGIRequest.SendInput(const ABuffer: pchar; ASize: integer): integer;
+begin
+ { first send current buffer if any }
+ if FInputBuffer <> nil then
+ begin
+ Result := SendBuffer;
+ if FInputBuffer <> nil then exit;
+ end else Result := 0;
+ if Result >= ASize then exit;
+ if FInputBuffer = nil then
+ begin
+ FInputBuffer := ABuffer+Result;
+ FInputSize := ASize-Result;
+ FHeader.ReqType := FCGI_STDIN;
+ SetContentLength(FInputSize);
+ AppendString(FBuffer, @FHeader, sizeof(FHeader));
+ end;
+ Inc(Result, SendBuffer);
+end;
+
+procedure TLFastCGIRequest.RewindBuffer;
+begin
+ FBufferSendPos := 0;
+ FHeaderPos := -1;
+ { rewind stringbuffer }
+ FBuffer.Pos := FBuffer.Memory;
+end;
+
+function TLFastCGIRequest.SendPrivateBuffer: boolean;
+var
+ lWritten: integer;
+begin
+ { nothing to send ? }
+ if FBuffer.Pos-FBuffer.Memory = FBufferSendPos then
+ exit(true);
+ { already a queue and we are not first in line ? no use in trying to send then }
+ if (FClient.FSendRequest = nil) or (FClient.FSendRequest = Self) then
+ begin
+ lWritten := FClient.Send(FBuffer.Memory[FBufferSendPos],
+ FBuffer.Pos-FBuffer.Memory-FBufferSendPos);
+ Inc(FBufferSendPos, lWritten);
+ Result := FBufferSendPos = FBuffer.Pos-FBuffer.Memory;
+ { do not rewind buffer, unless remote side has had chance to disconnect }
+ if Result then
+ RewindBuffer;
+ end else
+ Result := false;
+ if not Result then
+ FClient.AddToSendQueue(Self);
+end;
+
+function TLFastCGIRequest.SendBuffer: integer;
+var
+ lWritten: integer;
+begin
+ { already a queue and we are not first in line ? no use in trying to send then }
+ if (FClient.FSendRequest <> nil) and (FClient.FSendRequest <> Self) then
+ exit(0);
+
+ { header to be sent? }
+ if not SendPrivateBuffer then exit(0);
+ { first write request header, then wait for possible disconnect }
+ if FBufferSendPos > 0 then exit(0);
+ if FInputBuffer = nil then exit(0);
+
+ lWritten := FClient.Send(FInputBuffer^, FInputSize);
+ Inc(FInputBuffer, lWritten);
+ Dec(FInputSize, lWritten);
+ if FInputSize = 0 then
+ begin
+ FInputBuffer := nil;
+ AppendString(FBuffer, @PaddingBuffer[0], FHeader.PaddingLength);
+ end else
+ FClient.AddToSendQueue(Self);
+ Result := lWritten;
+end;
+
+procedure TLFastCGIRequest.SendEmptyRec(AType: integer);
+begin
+ FHeader.ReqType := AType;
+ SetContentLength(0);
+ AppendString(FBuffer, @FHeader, sizeof(FHeader));
+ { no padding needed for empty string }
+end;
+
+procedure TLFastCGIRequest.DoneParams;
+begin
+ SendEmptyRec(FCGI_PARAMS);
+end;
+
+procedure TLFastCGIRequest.DoneInput;
+begin
+ SendEmptyRec(FCGI_STDIN);
+ SendPrivateBuffer;
+end;
+
+procedure TLFastCGIRequest.AbortRequest;
+begin
+ FHeader.ReqType := FCGI_ABORT_REQUEST;
+ SetContentLength(0);
+ AppendString(FBuffer, @FHeader, sizeof(FHeader));
+ SendPrivateBuffer;
+end;
+
+{ TLFastCGIClient }
+
+const
+ DataBufferSize = 64*1024-1;
+
+constructor TLFastCGIClient.Create(AOwner: TComponent);
+begin
+ inherited;
+
+ FBuffer := GetMem(DataBufferSize+1);
+ FBufferPos := FBuffer;
+ FBufferEnd := FBuffer;
+ FRequests := AllocMem(sizeof(TLFastCGIRequest));
+ FRequestsCount := 1;
+ FFreeRequest := nil;
+ OnReceive := @HandleReceive;
+ OnCanSend := @HandleSend;
+end;
+
+destructor TLFastCGIClient.Destroy;
+var
+ I: integer;
+begin
+ for I := 0 to FNextRequestID-1 do
+ FRequests[I].Free;
+ FreeMem(FRequests);
+ FreeMem(FBuffer);
+ inherited;
+end;
+
+function TLFastCGIClient.GetBuffer(ABuffer: pchar; ASize: integer): integer;
+begin
+ Result := FBufferEnd - FBufferPos;
+ if Result > FContentLength then
+ Result := FContentLength;
+ if Result > ASize then
+ Result := ASize;
+ Move(FBufferPos^, ABuffer^, Result);
+ Inc(FBufferPos, Result);
+ Dec(FContentLength, Result);
+ { buffer empty? reset }
+ if FBufferPos = FBufferEnd then
+ begin
+ FBufferPos := FBuffer;
+ FBufferEnd := FBuffer;
+ end;
+end;
+
+procedure TLFastCGIClient.ConnectEvent(ASocket: TLHandle);
+begin
+ if FState = fsStartingServer then
+ FPool.FSpawnState := ssSpawned;
+ FState := fsHeader;
+ if FPool <> nil then
+ FPool.AddToFreeClients(Self);
+
+ inherited;
+end;
+
+procedure TLFastCGIClient.DisconnectEvent(ASocket: TLHandle);
+var
+ I: integer;
+ needReconnect: boolean;
+begin
+ inherited;
+ FRequestsSent := 0;
+ needReconnect := false;
+ for I := 0 to FNextRequestID-1 do
+ if FRequests[I].FNextFree = nil then
+ begin
+ { see if buffer contains request, then assume we can resend that }
+ if FRequests[I].FBufferSendPos > 0 then
+ begin
+ needReconnect := true;
+ FRequests[I].FBufferSendPos := 0;
+ FRequests[I].SendPrivateBuffer;
+ end else
+ if FRequests[I].FBuffer.Memory = FRequests[I].FBuffer.Pos then
+ needReconnect := true
+ else
+ FRequests[I].EndRequest;
+ end;
+ if needReconnect then
+ Connect;
+end;
+
+procedure TLFastCGIClient.ErrorEvent(const Msg: string; ASocket: TLHandle);
+begin
+ if (FState = fsConnectingAgain)
+ or ((FState = fsConnecting) and (FPool.FSpawnState = ssSpawned)) then
+ begin
+ FRequest.DoEndRequest;
+ EndRequest(FRequest);
+ FState := fsIdle;
+ end else
+ if FState = fsConnecting then
+ begin
+ FPool.StartServer;
+ FState := fsStartingServer;
+ end;
+end;
+
+procedure TLFastCGIClient.HandleGetValuesResult;
+var
+ lNameLen, lValueLen, lIntVal, lCode: integer;
+ lBufferPtr: pchar;
+ lPrevChar: char;
+
+ procedure GetIntVal;
+ begin
+ lPrevChar := lBufferPtr[lNameLen+lValueLen];
+ lBufferPtr[lNameLen+lValueLen] := #0;
+ Val(lBufferPtr+lNameLen, lIntVal, lCode);
+ lBufferPtr[lNameLen+lValueLen] := lPrevChar;
+ end;
+
+begin
+ repeat
+ lBufferPtr := FBufferPos;
+ Inc(lBufferPtr, GetFastCGIStringSize(PByte(lBufferPtr), lNameLen));
+ Inc(lBufferPtr, GetFastCGIStringSize(PByte(lBufferPtr), lValueLen));
+ if lBufferPtr + lNameLen + lValueLen > FBufferEnd then exit;
+ if StrLComp(lBufferPtr, 'FCGI_MAX_REQS', lNameLen) = 0 then
+ begin
+ GetIntVal;
+ if (lCode = 0) and (FRequestsCount <> lIntVal) then
+ begin
+ FRequestsCount := lIntVal;
+ ReallocMem(FRequests, sizeof(TLFastCGIRequest)*lIntVal);
+ end;
+ end else
+ if StrLComp(lBufferPtr, 'FCGI_MAX_CONNS', lNameLen) = 0 then
+ begin
+ GetIntVal;
+ if lCode = 0 then
+ FPool.ClientsMax := lIntVal;
+ end;
+ Inc(lBufferPtr, lNameLen+lValueLen);
+ Dec(FContentLength, lBufferPtr-FBufferPos);
+ FBufferPos := lBufferPtr;
+ until FContentLength = 0;
+end;
+
+procedure TLFastCGIClient.HandleReceive(ASocket: TLSocket);
+var
+ lRead: integer;
+begin
+ lRead := Get(FBufferEnd^, DataBufferSize-PtrUInt(FBufferEnd-FBuffer));
+ if lRead = 0 then exit;
+ { remote side has had chance to disconnect, clear buffer }
+ Inc(FBufferEnd, lRead);
+ ParseBuffer;
+end;
+
+procedure TLFastCGIClient.HandleSend(ASocket: TLSocket);
+var
+ lRequest: TLFastCGIRequest;
+begin
+ if FSendRequest = nil then exit;
+ lRequest := FSendRequest.FNextSend;
+ repeat
+ if not lRequest.SendPrivateBuffer or not lRequest.HandleSend then
+ exit;
+
+ lRequest.FNextSend := nil;
+ { only this one left in list ? }
+ if FSendRequest = lRequest then
+ begin
+ FSendRequest := nil;
+ exit;
+ end else begin
+ lRequest := lRequest.FNextSend;
+ FSendRequest.FNextSend := lRequest;
+ end;
+ until false;
+end;
+
+procedure TLFastCGIClient.AddToSendQueue(ARequest: TLFastCGIRequest);
+begin
+ if ARequest.FNextSend <> nil then exit;
+
+ if FSendRequest = nil then
+ FSendRequest := ARequest
+ else
+ ARequest.FNextSend := FSendRequest.FNextSend;
+ FSendRequest.FNextSend := ARequest;
+end;
+
+procedure TLFastCGIClient.ParseBuffer;
+var
+ lHeader: PFCGI_Header;
+ lReqIndex: integer;
+begin
+ repeat
+ case FState of
+ fsHeader:
+ begin
+ if FBufferEnd-FBufferPos < sizeof(FCGI_Header) then
+ exit;
+ lHeader := PFCGI_Header(FBufferPos);
+ FReqType := lHeader^.ReqType;
+ lReqIndex := (lHeader^.RequestIDB1 shl 8) or lHeader^.RequestIDB0;
+ FContentLength := (lHeader^.ContentLengthB1 shl 8) or lHeader^.ContentLengthB0;
+ FPaddingLength := lHeader^.PaddingLength;
+ Inc(FBufferPos, sizeof(lHeader^));
+ if lReqIndex > 0 then
+ Dec(lReqIndex);
+ if (lReqIndex < FRequestsCount) and (FRequests[lReqIndex] <> nil) then
+ begin
+ FRequest := FRequests[lReqIndex];
+ if FContentLength > 0 then
+ FState := fsData
+ else begin
+ FRequest.HandleReceiveEnd;
+ Flush;
+ end;
+ end else
+ Flush;
+ end;
+ fsData:
+ begin
+ FRequest.HandleReceive;
+ if FContentLength = 0 then
+ Flush
+ else begin
+ FRequest.FOutputPending := true;
+ exit;
+ end;
+ end;
+ fsFlush: Flush;
+ end;
+ until FBufferPos = FBufferEnd;
+end;
+
+procedure TLFastCGIClient.Flush;
+
+ function FlushSize(var ANumBytes: integer): boolean;
+ var
+ lFlushBytes: integer;
+ begin
+ lFlushBytes := ANumBytes;
+ if lFlushBytes > FBufferEnd - FBufferPos then
+ lFlushBytes := FBufferEnd - FBufferPos;
+ Dec(ANumBytes, lFlushBytes);
+ Inc(FBufferPos, lFlushBytes);
+ Result := ANumBytes = 0;
+ end;
+
+begin
+ FState := fsFlush;
+ if FlushSize(FContentLength) and FlushSize(FPaddingLength) then
+ begin
+ { buffer empty? reset }
+ if FBufferPos = FBufferEnd then
+ begin
+ FBufferPos := FBuffer;
+ FBufferEnd := FBuffer;
+ end;
+ FState := fsHeader;
+ FRequest := nil;
+ end;
+end;
+
+function TLFastCGIClient.CreateRequester: TLFastCGIRequest;
+begin
+ if FRequests[FNextRequestID] = nil then
+ FRequests[FNextRequestID] := TLFastCGIRequest.Create;
+ Result := FRequests[FNextRequestID];
+ Inc(FNextRequestID);
+ Result.FClient := Self;
+ Result.ID := FNextRequestID; { request ids start at 1 }
+end;
+
+function TLFastCGIClient.Connect: Boolean;
+begin
+ Result := inherited Connect(FPool.Host, FPool.Port);
+ FRequest := FRequests[0];
+ if FRequest.FBuffer.Pos = FRequest.FBuffer.Memory then
+ FRequest.SendGetValues;
+ if FState <> fsStartingServer then
+ FState := fsConnecting
+ else
+ FState := fsConnectingAgain;
+end;
+
+function TLFastCGIClient.BeginRequest(AType: integer): TLFastCGIRequest;
+begin
+ if FFreeRequest <> nil then
+ begin
+ Result := FFreeRequest.FNextFree;
+ if FFreeRequest = FFreeRequest.FNextFree then
+ FFreeRequest := nil
+ else
+ FFreeRequest.FNextFree := FFreeRequest.FNextFree.FNextFree;
+ Result.FNextFree := nil;
+ end else
+ if FNextRequestID = FRequestsCount then
+ exit(nil)
+ else begin
+ Result := CreateRequester;
+ end;
+
+ if not Connected then
+ Connect;
+
+ Result.SendBeginRequest(AType);
+ Inc(FRequestsSent);
+end;
+
+procedure TLFastCGIClient.EndRequest(ARequest: TLFastCGIRequest);
+begin
+ if FFreeRequest <> nil then
+ ARequest.FNextFree := FFreeRequest.FNextFree
+ else
+ FFreeRequest := ARequest;
+ FFreeRequest.FNextFree := ARequest;
+ if FPool <> nil then
+ FPool.EndRequest(Self);
+end;
+
+{ TLFastCGIPool }
+
+constructor TLFastCGIPool.Create;
+begin
+ FClientsMax := 1;
+ FMaxRequestsConn := 1;
+ inherited;
+end;
+
+destructor TLFastCGIPool.Destroy;
+var
+ I: integer;
+begin
+ for I := 0 to FClientsAvail-1 do
+ FClients[I].Free;
+ FreeMem(FClients);
+ if FTimer <> nil then
+ FTimer.Free;
+ inherited;
+end;
+
+function TLFastCGIPool.CreateClient: TLFastCGIClient;
+begin
+ if FClientsAvail = FClientsCount then
+ begin
+ Inc(FClientsCount, 64);
+ ReallocMem(FClients, FClientsCount*sizeof(TLFastCGIRequest));
+ end;
+ Result := TLFastCGIClient.Create(nil);
+ Result.FPool := Self;
+ Result.Eventer := FEventer;
+ FClients[FClientsAvail] := Result;
+ Inc(FClientsAvail);
+end;
+
+function TLFastCGIPool.BeginRequest(AType: integer): TLFastCGIRequest;
+var
+ lTempClient: TLFastCGIClient;
+begin
+ Result := nil;
+ while FFreeClient <> nil do
+ begin
+ lTempClient := FFreeClient.FNextFree;
+ Result := lTempClient.BeginRequest(AType);
+ if Result <> nil then break;
+ { Result = nil -> no free requesters on next free client }
+ if lTempClient = FFreeClient then
+ FFreeClient := nil
+ else
+ FFreeClient.FNextFree := lTempClient.FNextFree;
+ lTempClient.FNextFree := nil;
+ end;
+
+ { all clients busy }
+ if Result = nil then
+ if FClientsAvail < FClientsMax then
+ Result := CreateClient.BeginRequest(AType);
+end;
+
+procedure TLFastCGIPool.EndRequest(AClient: TLFastCGIClient);
+begin
+ { TODO: wait for other requests to be completed }
+ if AClient.RequestsSent = FMaxRequestsConn then
+ AClient.Disconnect;
+ AddToFreeClients(AClient);
+end;
+
+procedure TLFastCGIPool.AddToFreeClients(AClient: TLFastCGIClient);
+begin
+ if AClient.FNextFree <> nil then exit;
+
+ if FFreeClient = nil then
+ FFreeClient := AClient
+ else
+ AClient.FNextFree := FFreeClient.FNextFree;
+ FFreeClient.FNextFree := AClient;
+end;
+
+procedure TLFastCGIPool.ConnectClients(Sender: TObject);
+var
+ I: integer;
+begin
+ for I := 0 to FClientsAvail-1 do
+ if FClients[I].FState = fsStartingServer then
+ FClients[I].Connect;
+end;
+
+procedure TLFastCGIPool.StartServer;
+begin
+ if FSpawnState = ssNone then
+ begin
+ FSpawnState := ssSpawning;
+ SpawnFCGIProcess(FAppName, FAppEnv, FPort);
+ if FTimer = nil then
+ FTimer := TLTimer.Create;
+ FTimer.OneShot := true;
+ FTimer.OnTimer := @ConnectClients;
+ end;
+ FTimer.Interval := 2000;
+end;
+
+end.
diff --git a/utils/fppkg/lnet/lftp.pp b/utils/fppkg/lnet/lftp.pp
index 86bcceb25a..b900eb14f8 100644
--- a/utils/fppkg/lnet/lftp.pp
+++ b/utils/fppkg/lnet/lftp.pp
@@ -35,9 +35,9 @@ type
TLFTP = class;
TLFTPClient = class;
- TLFTPStatus = (fsNone, fsCon, fsAuth, fsPasv, fsPort, fsList, fsRetr, fsStor,
- fsType, fsCWD, fsMKD, fsRMD, fsDEL, fsRNFR, fsRNTO, fsSYS,
- fsFeat, fsPWD, fsHelp, fsLast);
+ TLFTPStatus = (fsNone, fsCon, fsAuth, fsPass, fsPasv, fsPort, fsList, fsRetr,
+ fsStor, fsType, fsCWD, fsMKD, fsRMD, fsDEL, fsRNFR, fsRNTO,
+ fsSYS, fsFeat, fsPWD, fsHelp, fsLast);
TLFTPStatusSet = set of TLFTPStatus;
@@ -131,6 +131,7 @@ type
procedure OnControlEr(const msg: string; aSocket: TLSocket);
procedure OnControlRe(aSocket: TLSocket);
procedure OnControlCo(aSocket: TLSocket);
+ procedure OnControlDs(aSocket: TLSocket);
function GetTransfer: Boolean;
@@ -170,6 +171,8 @@ type
function Authenticate(const aUsername, aPassword: string): Boolean;
+ function SendPassword(const aPassword: string): Boolean;
+
function GetData(var aData; const aSize: Integer): Integer;
function GetDataMessage: string;
@@ -211,6 +214,8 @@ type
property OnFailure: TLFTPClientStatusEvent read FOnFailure write FOnFailure;
end;
+ function FTPStatusToStr(const aStatus: TLFTPStatus): string;
+
implementation
uses
@@ -222,7 +227,7 @@ const
EMPTY_REC: TLFTPStatusRec = (Status: fsNone; Args: ('', ''));
- FTPStatusStr: array[TLFTPStatus] of string = ('None', 'Connect', 'Authenticate',
+ FTPStatusStr: array[TLFTPStatus] of string = ('None', 'Connect', 'Authenticate', 'Password',
'Passive', 'Active', 'List', 'Retrieve',
'Store', 'Type', 'CWD', 'MKDIR',
'RMDIR', 'Delete', 'RenameFrom',
@@ -258,13 +263,18 @@ begin
Result.Args[2] := Arg2;
end;
+function FTPStatusToStr(const aStatus: TLFTPStatus): string;
+begin
+ Result := FTPStatusStr[aStatus];
+end;
+
{$i lcontainers.inc}
{ TLFTP }
function TLFTP.GetConnected: Boolean;
begin
- Result := FControl.Connected;
+ Result := FControl.Connected;
end;
function TLFTP.GetTimeout: DWord;
@@ -331,6 +341,7 @@ begin
FControl.OnReceive := @OnControlRe;
FControl.OnConnect := @OnControlCo;
FControl.OnError := @OnControlEr;
+ FControl.OnDisconnect := @OnControlDs;
FData.OnReceive := @OnRe;
FData.OnDisconnect := @OnDs;
@@ -372,7 +383,6 @@ end;
procedure TLFTPClient.OnDs(aSocket: TLSocket);
begin
- // TODO: figure it out brainiac
FSending := False;
Writedbg(['Disconnected']);
end;
@@ -409,6 +419,12 @@ begin
FOnConnect(aSocket);
end;
+procedure TLFTPClient.OnControlDs(aSocket: TLSocket);
+begin
+ if Assigned(FOnError) then
+ FOnError('Connection lost', aSocket);
+end;
+
function TLFTPClient.GetTransfer: Boolean;
begin
Result := FData.Connected;
@@ -586,10 +602,22 @@ begin
FStatus.Remove;
end;
331,
- 332: begin
- FStatusFlags[FStatus.First.Status] := False;
- FControl.SendMessage('PASS ' + FPassword + FLE);
- end;
+ 332: SendPassword(FPassword);
+ else
+ begin
+ FStatusFlags[FStatus.First.Status] := False;
+ Eventize(FStatus.First.Status, False);
+ FStatus.Remove;
+ end;
+ end;
+
+ fsPass : case x of
+ 230:
+ begin
+ FStatusFlags[FStatus.First.Status] := True;
+ Eventize(FStatus.First.Status, True);
+ FStatus.Remove;
+ end;
else
begin
FStatusFlags[FStatus.First.Status] := False;
@@ -819,6 +847,7 @@ begin
case Status of
fsNone : Exit;
fsAuth : Authenticate(Args[1], Args[2]);
+ fsPass : SendPassword(Args[1]);
fsList : List(Args[1]);
fsRetr : Retrieve(Args[1]);
fsStor : Put(Args[1]);
@@ -909,6 +938,17 @@ begin
end;
end;
+function TLFTPClient.SendPassword(const aPassword: string): Boolean;
+begin
+ Result := not FPipeLine;
+ if CanContinue(fsPass, aPassword, '') then begin
+ FControl.SendMessage('PASS ' + aPassword + FLE);
+ FStatus.Insert(MakeStatusRec(fsPass, '', ''));
+ Result := True;
+ end;
+end;
+
+
function TLFTPClient.Retrieve(const FileName: string): Boolean;
begin
Result := not FPipeLine;
diff --git a/utils/fppkg/lnet/lhttp.pp b/utils/fppkg/lnet/lhttp.pp
new file mode 100644
index 0000000000..c16e10e0ac
--- /dev/null
+++ b/utils/fppkg/lnet/lhttp.pp
@@ -0,0 +1,2264 @@
+{ HTTP server and client components
+
+ Copyright (C) 2006 Micha Nelissen
+
+ This library is Free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+ for more details.
+
+ You should have received a Copy of the GNU Library General Public License
+ along with This library; if not, Write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ This license has been modified. See file LICENSE.ADDON for more information.
+ Should you find these sources without a LICENSE File, please contact
+ me at ales@chello.sk
+}
+
+unit lhttp;
+
+{$mode objfpc}{$h+}
+{$inline on}
+
+interface
+
+uses
+ classes, sysutils, lnet, levents, lhttputil, lstrbuffer;
+
+type
+ TLHTTPMethod = (hmHead, hmGet, hmPost, hmUnknown);
+ TLHTTPParameter = (hpConnection, hpContentLength, hpContentType,
+ hpAccept, hpAcceptCharset, hpAcceptEncoding, hpAcceptLanguage, hpHost,
+ hpFrom, hpReferer, hpUserAgent, hpRange, hpTransferEncoding,
+ hpIfModifiedSince, hpIfUnmodifiedSince, hpCookie);
+ TLHTTPStatus = (hsUnknown, hsOK, hsNoContent, hsMovedPermanently, hsFound, hsNotModified,
+ hsBadRequest, hsForbidden, hsNotFound, hsPreconditionFailed, hsRequestTooLong,
+ hsInternalError, hsNotImplemented, hsNotAllowed);
+ TLHTTPTransferEncoding = (teIdentity, teChunked);
+ TLHTTPClientError = (ceNone, ceMalformedStatusLine, ceVersionNotSupported,
+ ceUnsupportedEncoding);
+
+const
+ HTTPDisconnectStatuses = [hsBadRequest, hsRequestTooLong, hsForbidden,
+ hsInternalError, hsNotAllowed];
+ HTTPMethodStrings: array[TLHTTPMethod] of string =
+ ('HEAD', 'GET', 'POST', '');
+ HTTPParameterStrings: array[TLHTTPParameter] of string =
+ ('CONNECTION', 'CONTENT-LENGTH', 'CONTENT-TYPE', 'ACCEPT',
+ 'ACCEPT-CHARSET', 'ACCEPT-ENCODING', 'ACCEPT-LANGUAGE', 'HOST',
+ 'FROM', 'REFERER', 'USER-AGENT', 'RANGE', 'TRANSFER-ENCODING',
+ 'IF-MODIFIED-SINCE', 'IF-UNMODIFIED-SINCE', 'COOKIE');
+ HTTPStatusCodes: array[TLHTTPStatus] of dword =
+ (0, 200, 204, 301, 302, 304, 400, 403, 404, 412, 414, 500, 501, 504);
+ HTTPTexts: array[TLHTTPStatus] of string =
+ ('', 'OK', 'No Content', 'Moved Permanently', 'Found', 'Not Modified', 'Bad Request', 'Forbidden',
+ 'Not Found', 'Precondition Failed', 'Request Too Long', 'Internal Error',
+ 'Method Not Implemented', 'Method Not Allowed');
+ HTTPDescriptions: array[TLHTTPStatus] of string = (
+ { hsUnknown }
+ '',
+ { hsOK }
+ '',
+ { hsNoContent }
+ '',
+ { hsMovedPermanently }
+ '',
+ { hsFound }
+ '',
+ { hsNotModified }
+ '',
+ { hsBadRequest }
+ '
400 Bad Request'+#10+
+ 'Bad Request
'+#10+
+ 'Your browser did a request this server did not understand.
'+#10+
+ ''+#10,
+ { hsForbidden }
+ '403 Forbidden'+#10+
+ 'Forbidden
'+#10+
+ 'You do not have permission to access this resource.
'+#10+
+ ''+#10,
+ { hsNotFound }
+ '404 Not Found'+#10+
+ 'Not Found
'+#10+
+ 'The requested URL was not found on this server.
'+#10+
+ ''+#10,
+ { hsPreconditionFailed }
+ '412 Precondition Failed'+#10+
+ 'Precondition Failed
'+#10+
+ 'The precondition on the request evaluated to false.
'+#10+
+ ''+#10,
+ { hsRequestTooLong }
+ '414 Request Too Long'+#10+
+ 'Bad Request
'+#10+
+ 'Your browser did a request that was too long for this server to parse.
'+#10+
+ ''+#10,
+ { hsInternalError }
+ '500 Internal Error'+#10+
+ 'Internal Error
'+#10+
+ 'An error occurred while generating the content for this request.
'+#10+
+ ''+#10,
+ { hsNotImplemented }
+ '501 Method Not Implemented'+#10+
+ 'Method Not Implemented
'+#10+
+ 'The method used in the request is invalid.
'+#10+
+ ''+#10,
+ { hsNotAllowed }
+ '504 Method Not Allowed'+#10+
+ 'Method Not Allowed
'+#10+
+ 'The method used in the request is not allowed on the resource specified in the URL.
'+#10+
+ ''+#10);
+
+
+type
+ TLHTTPSocket = class;
+ TLHTTPConnection = class;
+ TLHTTPClientSocket = class;
+
+ PRequestInfo = ^TRequestInfo;
+ TRequestInfo = record
+ RequestType: TLHTTPMethod;
+ DateTime: TDateTime;
+ Method: pchar;
+ Argument: pchar;
+ QueryParams: pchar;
+ VersionStr: pchar;
+ Version: dword;
+ end;
+
+ PClientRequest = ^TClientRequest;
+ TClientRequest = record
+ Method: TLHTTPMethod;
+ URI: string;
+ QueryParams: string;
+ RangeStart: qword;
+ RangeEnd: qword;
+ end;
+
+ PClientResponse = ^TClientResponse;
+ TClientResponse = record
+ Status: TLHTTPStatus;
+ Version: dword;
+ Reason: string;
+ end;
+
+ PHeaderOutInfo = ^THeaderOutInfo;
+ THeaderOutInfo = record
+ ContentLength: integer;
+ TransferEncoding: TLHTTPTransferEncoding;
+ ExtraHeaders: TStringBuffer;
+ Version: dword;
+ end;
+
+ PResponseInfo = ^TResponseInfo;
+ TResponseInfo = record
+ Status: TLHTTPStatus;
+ ContentType: string;
+ ContentCharset: string;
+ LastModified: TDateTime;
+ end;
+
+ TWriteBlockStatus = (wsPendingData, wsWaitingData, wsDone);
+ TWriteBlockMethod = function: TWriteBlockStatus of object;
+
+ TOutputItem = class(TObject)
+ protected
+ FBuffer: pchar;
+ FBufferPos: integer;
+ FBufferSize: integer;
+ FBufferOffset: integer;
+ FOutputPending: boolean;
+ FEof: boolean;
+ FPrev: TOutputItem;
+ FNext: TOutputItem;
+ FPrevDelayFree: TOutputItem;
+ FNextDelayFree: TOutputItem;
+ FSocket: TLHTTPSocket;
+ FWriteBlock: TWriteBlockMethod;
+
+ procedure DoneInput; virtual;
+ function HandleInput(ABuffer: pchar; ASize: integer): integer; virtual;
+ function WriteBlock: TWriteBlockStatus; virtual;
+ public
+ constructor Create(ASocket: TLHTTPSocket);
+ destructor Destroy; override;
+
+ procedure LogError(const AMessage: string);
+
+ property Socket: TLHTTPSocket read FSocket;
+ end;
+
+ TProcMethod = procedure of object;
+
+ TBufferOutput = class(TOutputItem)
+ protected
+ FPrepareBuffer: TProcMethod;
+ FFinishBuffer: TProcMethod;
+ FBufferMemSize: integer;
+
+ procedure PrepareBuffer;
+ procedure PrepareChunk;
+ procedure FinishBuffer;
+ procedure FinishChunk;
+ procedure SelectChunked;
+ procedure SelectBuffered;
+ procedure SelectPlain;
+ procedure PrependBufferOutput(MinBufferSize: integer);
+ procedure PrependStreamOutput(AStream: TStream; AFree: boolean);
+ function FillBuffer: TWriteBlockStatus; virtual; abstract;
+ function WriteChunk: TWriteBlockStatus;
+ function WriteBuffer: TWriteBlockStatus;
+ function WritePlain: TWriteBlockStatus;
+ function WriteBlock: TWriteBlockStatus; override;
+ public
+ constructor Create(ASocket: TLHTTPSocket);
+ destructor Destroy; override;
+
+ procedure Add(ABuf: pointer; ASize: integer);
+ procedure Add(const AStr: string);
+ procedure Add(AStream: TStream; AQueue: boolean = false; AFree: boolean = true);
+ end;
+
+ TMemoryOutput = class(TOutputItem)
+ protected
+ FFreeBuffer: boolean;
+ public
+ constructor Create(ASocket: TLHTTPSocket; ABuffer: pointer;
+ ABufferOffset, ABufferSize: integer; AFreeBuffer: boolean);
+ destructor Destroy; override;
+ end;
+
+ TStreamOutput = class(TBufferOutput)
+ protected
+ FStream: TStream;
+ FFreeStream: boolean;
+ FStreamSize: integer;
+
+ function FillBuffer: TWriteBlockStatus; override;
+ public
+ constructor Create(ASocket: TLHTTPSocket; AStream: TStream; AFreeStream: boolean);
+ destructor Destroy; override;
+ end;
+
+ TMemoryStreamOutput = class(TOutputItem)
+ protected
+ FFreeStream: boolean;
+ FStream: TMemoryStream;
+
+ function WriteBlock: TWriteBlockStatus; override;
+ public
+ constructor Create(ASocket: TLHTTPSocket; AStream: TMemoryStream; AFreeStream: boolean);
+ destructor Destroy; override;
+ end;
+
+ TChunkState = (csInitial, csData, csDataEnd, csTrailer, csFinished);
+ TLHTTPParameterArray = array[TLHTTPParameter] of pchar;
+
+ TParseBufferMethod = function: boolean of object;
+ TLInputEvent = function(ASocket: TLHTTPClientSocket; ABuffer: pchar; ASize: integer): integer of object;
+ TLCanWriteEvent = procedure(ASocket: TLHTTPClientSocket; var OutputEof: TWriteBlockStatus) of object;
+ TLHTTPClientEvent = procedure(ASocket: TLHTTPClientSocket) of object;
+
+ TLHTTPConnection = class(TLTcp)
+ protected
+ procedure CanSendEvent(aSocket: TLHandle); override;
+ procedure LogAccess(const AMessage: string); virtual;
+ procedure ReceiveEvent(aSocket: TLHandle); override;
+ public
+ destructor Destroy; override;
+ end;
+
+ TLHTTPSocket = class(TLSocket)
+ protected
+ FBuffer: pchar;
+ FBufferPos: pchar;
+ FBufferEnd: pchar;
+ FBufferSize: integer;
+ FRequestBuffer: pchar;
+ FRequestPos: pchar;
+ FRequestInputDone: boolean;
+ FRequestHeaderDone: boolean;
+ FOutputDone: boolean;
+ FInputRemaining: integer;
+ FChunkState: TChunkState;
+ FCurrentInput: TOutputItem;
+ FCurrentOutput: TOutputItem;
+ FLastOutput: TOutputItem;
+ FKeepAlive: boolean;
+ FParseBuffer: TParseBufferMethod;
+ FParameters: TLHTTPParameterArray;
+ FDelayFreeItems: TOutputItem;
+
+ procedure AddContentLength(ALength: integer); virtual; abstract;
+ function CalcAvailableBufferSpace: integer;
+ procedure DelayFree(AOutputItem: TOutputItem);
+ procedure Disconnect; override;
+ procedure DoneBuffer(AOutput: TBufferOutput); virtual;
+ procedure FreeDelayFreeItems;
+ procedure LogAccess(const AMessage: string); virtual;
+ procedure LogMessage; virtual;
+ procedure FlushRequest; virtual;
+ procedure PackRequestBuffer;
+ procedure PackInputBuffer;
+ function ParseRequest: boolean;
+ function ParseEntityPlain: boolean;
+ function ParseEntityChunked: boolean;
+ procedure ParseLine(pLineEnd: pchar); virtual;
+ procedure ParseParameterLine(pLineEnd: pchar);
+ function ProcessEncoding: boolean;
+ procedure ProcessHeaders; virtual; abstract;
+ procedure RelocateVariable(var AVar: pchar);
+ procedure RelocateVariables; virtual;
+ procedure ResetDefaults; virtual;
+ function SetupEncoding(AOutputItem: TBufferOutput; AHeaderOut: PHeaderOutInfo): boolean;
+ procedure WriteError(AStatus: TLHTTPStatus); virtual;
+ public
+ constructor Create; override;
+ destructor Destroy; override;
+
+ procedure AddToOutput(AOutputItem: TOutputItem);
+ procedure PrependOutput(ANewItem, AItem: TOutputItem);
+ procedure RemoveOutput(AOutputItem: TOutputItem);
+ procedure HandleReceive;
+ function ParseBuffer: boolean;
+ procedure WriteBlock;
+
+ property Parameters: TLHTTPParameterArray read FParameters;
+ end;
+
+ { http server }
+
+ TSetupEncodingState = (seNone, seWaitHeaders, seStartHeaders);
+
+ TLHTTPServerSocket = class(TLHTTPSocket)
+ protected
+ FLogMessage: TStringBuffer;
+ FRequestInfo: TRequestInfo;
+ FResponseInfo: TResponseInfo;
+ FHeaderOut: THeaderOutInfo;
+ FSetupEncodingState: TSetupEncodingState;
+
+ procedure AddContentLength(ALength: integer); override;
+ procedure DoneBuffer(AOutput: TBufferOutput); override;
+ procedure FlushRequest; override;
+ function HandleURI: TOutputItem; virtual;
+ procedure LogAccess(const AMessage: string); override;
+ procedure LogMessage; override;
+ procedure RelocateVariables; override;
+ procedure ResetDefaults; override;
+ procedure ParseLine(pLineEnd: pchar); override;
+ procedure ParseRequestLine(pLineEnd: pchar);
+ function PrepareResponse(AOutputItem: TOutputItem; ACustomErrorMessage: boolean): boolean;
+ procedure ProcessHeaders; override;
+ procedure WriteError(AStatus: TLHTTPStatus); override;
+ procedure WriteHeaders(AHeaderResponse, ADataResponse: TOutputItem);
+ public
+ constructor Create; override;
+ destructor Destroy; override;
+
+ function SetupEncoding(AOutputItem: TBufferOutput): boolean;
+ procedure StartMemoryResponse(AOutputItem: TMemoryOutput; ACustomErrorMessage: boolean = false);
+ procedure StartResponse(AOutputItem: TBufferOutput; ACustomErrorMessage: boolean = false);
+
+ property HeaderOut: THeaderOutInfo read FHeaderOut;
+ property RequestInfo: TRequestInfo read FRequestInfo;
+ property ResponseInfo: TResponseInfo read FResponseInfo;
+ end;
+
+ TURIHandler = class(TObject)
+ private
+ FNext: TURIHandler;
+ protected
+ function HandleURI(ASocket: TLHTTPServerSocket): TOutputItem; virtual; abstract;
+ procedure RegisterWithEventer(AEventer: TLEventer); virtual;
+ end;
+
+ TLAccessEvent = procedure(AMessage: string) of object;
+
+ TLHTTPServer = class(TLHTTPConnection)
+ protected
+ FHandlerList: TURIHandler;
+ FLogMessageTZString: string;
+ FServerSoftware: string;
+ FOnAccess: TLAccessEvent;
+
+ function HandleURI(ASocket: TLHTTPServerSocket): TOutputItem;
+ protected
+ procedure LogAccess(const AMessage: string); override;
+ procedure RegisterWithEventer; override;
+ public
+ constructor Create(AOwner: TComponent); override;
+
+ procedure RegisterHandler(AHandler: TURIHandler);
+
+ property ServerSoftware: string read FServerSoftware write FServerSoftware;
+ property OnAccess: TLAccessEvent read FOnAccess write FOnAccess;
+ end;
+
+ { http client }
+
+ TLHTTPClientSocket = class(TLHTTPSocket)
+ protected
+ FRequest: PClientRequest;
+ FResponse: PClientResponse;
+ FHeaderOut: PHeaderOutInfo;
+ FError: TLHTTPClientError;
+
+ procedure AddContentLength(ALength: integer); override;
+ function GetResponseReason: string;
+ function GetResponseStatus: TLHTTPStatus;
+ procedure Cancel(AError: TLHTTPClientError);
+ procedure ParseLine(pLineEnd: pchar); override;
+ procedure ParseStatusLine(pLineEnd: pchar);
+ procedure ProcessHeaders; override;
+ procedure ResetDefaults; override;
+ public
+ constructor Create; override;
+ destructor Destroy; override;
+
+ procedure SendRequest;
+
+ property Error: TLHTTPClientError read FError write FError;
+ property Response: PClientResponse read FResponse;
+ property ResponseReason: string read GetResponseReason;
+ property ResponseStatus: TLHTTPStatus read GetResponseStatus;
+ end;
+
+ TLHTTPClientState = (hcsIdle, hcsWaiting, hcsReceiving);
+
+ TLHTTPClient = class(TLHTTPConnection)
+ protected
+ FRequest: TClientRequest;
+ FResponse: TClientResponse;
+ FHeaderOut: THeaderOutInfo;
+ FState: TLHTTPClientState;
+ FPendingResponses: integer;
+ FOutputEof: boolean;
+ FOnCanWrite: TLCanWriteEvent;
+ FOnDoneInput: TLHTTPClientEvent;
+ FOnInput: TLInputEvent;
+ FOnProcessHeaders: TLHTTPClientEvent;
+
+ procedure ConnectEvent(aSocket: TLHandle); override;
+ procedure DoDoneInput(ASocket: TLHTTPClientSocket);
+ function DoHandleInput(ASocket: TLHTTPClientSocket; ABuffer: pchar; ASize: integer): integer;
+ procedure DoProcessHeaders(ASocket: TLHTTPClientSocket);
+ function DoWriteBlock(ASocket: TLHTTPClientSocket): TWriteBlockStatus;
+ function InitSocket(aSocket: TLSocket): TLSocket; override;
+ procedure InternalSendRequest;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+
+ procedure AddExtraHeader(const AHeader: string);
+ procedure ResetRange;
+ procedure SendRequest;
+
+ property ContentLength: integer read FHeaderOut.ContentLength write FHeaderOut.ContentLength;
+ property Method: TLHTTPMethod read FRequest.Method write FRequest.Method;
+ property PendingResponses: integer read FPendingResponses;
+ property RangeStart: qword read FRequest.RangeStart write FRequest.RangeStart;
+ property RangeEnd: qword read FRequest.RangeEnd write FRequest.RangeEnd;
+ property Request: TClientRequest read FRequest;
+ property State: TLHTTPClientState read FState;
+ property URI: string read FRequest.URI write FRequest.URI;
+ property Response: TClientResponse read FResponse;
+ property OnCanWrite: TLCanWriteEvent read FOnCanWrite write FOnCanWrite;
+ property OnDoneInput: TLHTTPClientEvent read FOnDoneInput write FOnDoneInput;
+ property OnInput: TLInputEvent read FOnInput write FOnInput;
+ property OnProcessHeaders: TLHTTPClientEvent read FOnProcessHeaders write FOnProcessHeaders;
+ end;
+
+implementation
+
+uses
+ lCommon;
+
+const
+ RequestBufferSize = 1024;
+ DataBufferSize = 16*1024;
+
+ BufferEmptyToWriteStatus: array[boolean] of TWriteBlockStatus =
+ (wsPendingData, wsDone);
+ EofToWriteStatus: array[boolean] of TWriteBlockStatus =
+ (wsWaitingData, wsDone);
+
+{ helper functions }
+
+function TrySingleDigit(ADigit: char; out OutDigit: byte): boolean;
+begin
+ Result := (ord(ADigit) >= ord('0')) and (ord(ADigit) <= ord('9'));
+ if not Result then exit;
+ OutDigit := ord(ADigit) - ord('0');
+end;
+
+function HTTPVersionCheck(AStr, AStrEnd: pchar; out AVersion: dword): boolean;
+var
+ lMajorVersion, lMinorVersion: byte;
+begin
+ Result := ((AStrEnd-AStr) = 8)
+ and CompareMem(AStr, pchar('HTTP/'), 5)
+ and TrySingleDigit(AStr[5], lMajorVersion)
+ and (AStr[6] = '.')
+ and TrySingleDigit(AStr[7], lMinorVersion);
+ AVersion := lMajorVersion * 10 + lMinorVersion;
+end;
+
+function CodeToHTTPStatus(ACode: dword): TLHTTPStatus;
+begin
+ for Result := Low(TLHTTPStatus) to High(TLHTTPStatus) do
+ if HTTPStatusCodes[Result] = ACode then exit;
+ Result := hsUnknown;
+end;
+
+const
+ HexDigits: array[0..15] of char = '0123456789ABCDEF';
+
+function HexReverse(AValue: dword; ABuffer: pchar): integer;
+begin
+ Result := 0;
+ repeat
+ ABuffer^ := HexDigits[AValue and $F];
+ AValue := AValue shr 4;
+ Dec(ABuffer);
+ Inc(Result);
+ until AValue = 0;
+end;
+
+procedure HexToInt(ABuffer: pchar; out AValue: dword; out ACode: integer);
+var
+ Val, Incr: dword;
+ Start: pchar;
+begin
+ Val := 0;
+ ACode := 0;
+ Start := ABuffer;
+ while ABuffer^ <> #0 do
+ begin
+ if (ABuffer^ >= '0') and (ABuffer^ <= '9') then
+ Incr := ord(ABuffer^) - ord('0')
+ else if (ABuffer^ >= 'A') and (ABuffer^ <= 'F') then
+ Incr := ord(ABuffer^) - ord('A') + 10
+ else if (ABuffer^ >= 'a') and (ABuffer^ <= 'f') then
+ Incr := ord(ABuffer^) - ord('a') + 10
+ else begin
+ ACode := ABuffer - Start + 1;
+ break;
+ end;
+ Val := (Val shl 4) + Incr;
+ Inc(ABuffer);
+ end;
+ AValue := Val;
+end;
+
+{ TURIHandler }
+
+procedure TURIHandler.RegisterWithEventer(AEventer: TLEventer);
+begin
+end;
+
+{ TOutputItem }
+
+constructor TOutputItem.Create(ASocket: TLHTTPSocket);
+begin
+ FSocket := ASocket;
+ inherited Create;
+end;
+
+destructor TOutputItem.Destroy;
+begin
+ if FSocket.FCurrentInput = Self then
+ FSocket.FCurrentInput := nil;
+
+ if FPrevDelayFree = nil then
+ FSocket.FDelayFreeItems := FNextDelayFree
+ else
+ FPrevDelayFree.FNextDelayFree := FNextDelayFree;
+ if FNextDelayFree <> nil then
+ FNextDelayFree.FPrevDelayFree := FPrevDelayFree;
+
+ inherited;
+end;
+
+procedure TOutputItem.DoneInput;
+begin
+end;
+
+function TOutputItem.HandleInput(ABuffer: pchar; ASize: integer): integer;
+begin
+ { discard input }
+ Result := ASize;
+end;
+
+procedure TOutputItem.LogError(const AMessage: string);
+begin
+ FSocket.LogError(AMessage, 0);
+end;
+
+function TOutputItem.WriteBlock: TWriteBlockStatus;
+var
+ lWritten: integer;
+begin
+ if FOutputPending then
+ begin
+ if FBufferSize > FBufferPos then
+ begin
+ lWritten := FSocket.Send(FBuffer[FBufferPos], FBufferSize-FBufferPos);
+ Inc(FBufferPos, lWritten);
+ end;
+ FOutputPending := FBufferPos < FBufferSize;
+ Result := BufferEmptyToWriteStatus[not FOutputPending];
+ end else
+ Result := EofToWriteStatus[FEof];
+end;
+
+const
+ ReserveChunkBytes = 12;
+
+constructor TBufferOutput.Create(ASocket: TLHTTPSocket);
+begin
+ inherited;
+ GetMem(FBuffer, DataBufferSize);
+ FWriteBlock := @WritePlain;
+ FPrepareBuffer := @PrepareBuffer;
+ FFinishBuffer := @FinishBuffer;
+ FBufferMemSize := DataBufferSize;
+end;
+
+destructor TBufferOutput.Destroy;
+begin
+ inherited;
+ FreeMem(FBuffer);
+end;
+
+procedure TBufferOutput.Add(ABuf: pointer; ASize: integer);
+var
+ copySize: integer;
+begin
+ repeat
+ copySize := FBufferSize-FBufferPos;
+ if copySize > ASize then
+ copySize := ASize;
+ Move(ABuf^, FBuffer[FBufferPos], copySize);
+ Inc(FBufferPos, copySize);
+ Dec(ASize, copySize);
+ if ASize = 0 then
+ break;
+ PrependBufferOutput(ASize);
+ until false;
+end;
+
+procedure TBufferOutput.Add(const AStr: string);
+begin
+ Add(PChar(AStr), Length(AStr));
+end;
+
+procedure TBufferOutput.PrependStreamOutput(AStream: TStream; AFree: boolean);
+begin
+ if AStream is TMemoryStream then
+ FSocket.PrependOutput(TMemoryStreamOutput.Create(FSocket, TMemoryStream(AStream), AFree), Self)
+ else
+ FSocket.PrependOutput(TStreamOutput.Create(FSocket, AStream, AFree), Self);
+end;
+
+procedure TBufferOutput.Add(AStream: TStream; AQueue: boolean = false;
+ AFree: boolean = true);
+var
+ size, copySize: integer;
+begin
+ size := AStream.Size - AStream.Position;
+ repeat
+ copySize := FBufferSize-FBufferPos;
+ if copySize > size then
+ copySize := size;
+ AStream.Read(FBuffer[FBufferPos], copySize);
+ Inc(FBufferPos, copySize);
+ Dec(size, copySize);
+ if size = 0 then
+ break;
+ if AQueue then
+ begin
+ PrependBufferOutput(0);
+ PrependStreamOutput(AStream, AFree);
+ end else begin
+ PrependBufferOutput(size);
+ end;
+ until false;
+end;
+
+procedure TBufferOutput.PrepareChunk;
+begin
+ { 12 bytes for starting space, 7 bytes to end: 0 }
+ FBufferPos := ReserveChunkBytes;
+ FBufferOffset := FBufferPos;
+ FBufferSize := FBufferMemSize-7;
+end;
+
+procedure TBufferOutput.FinishChunk;
+var
+ lOffset: integer;
+begin
+ lOffset := HexReverse(FBufferPos-FBufferOffset, FBuffer+FBufferOffset-3);
+ FBuffer[FBufferOffset-2] := #13;
+ FBuffer[FBufferOffset-1] := #10;
+ FBuffer[FBufferPos] := #13;
+ FBuffer[FBufferPos+1] := #10;
+ FBufferSize := FBufferPos+2;
+ FBufferPos := FBufferOffset-lOffset-2;
+end;
+
+procedure TBufferOutput.PrepareBuffer;
+ { also for "plain" encoding }
+begin
+ FBufferPos := 0;
+ FBufferOffset := 0;
+ FBufferSize := FBufferMemSize;
+end;
+
+procedure TBufferOutput.FinishBuffer;
+begin
+ { nothing to do }
+end;
+
+procedure TBufferOutput.PrependBufferOutput(MinBufferSize: integer);
+begin
+ FFinishBuffer();
+ FSocket.PrependOutput(TMemoryOutput.Create(FSocket, FBuffer, FBufferOffset,
+ FBufferPos, true), Self);
+ FBufferMemSize := MinBufferSize;
+ if FBufferMemSize < DataBufferSize then
+ FBufferMemSize := DataBufferSize;
+ FBuffer := GetMem(FBufferMemSize);
+ FPrepareBuffer();
+end;
+
+function TBufferOutput.WriteChunk: TWriteBlockStatus;
+begin
+ if not FOutputPending and not FEof then
+ begin
+ Result := FillBuffer;
+ FEof := Result = wsDone;
+ FOutputPending := FBufferPos > FBufferOffset;
+ if FOutputPending then
+ FinishChunk;
+ if FEof then
+ begin
+ if not FOutputPending then
+ begin
+ { FBufferPos/Size still in "fill mode" }
+ FBufferSize := 0;
+ FBufferPos := 0;
+ FOutputPending := true;
+ end;
+ FBuffer[FBufferSize] := '0';
+ FBuffer[FBufferSize+1] := #13;
+ FBuffer[FBufferSize+2] := #10;
+ { no trailer }
+ FBuffer[FBufferSize+3] := #13;
+ FBuffer[FBufferSize+4] := #10;
+ inc(FBufferSize, 5);
+ end;
+ end else
+ Result := EofToWriteStatus[FEof];
+ if FOutputPending then
+ begin
+ Result := inherited WriteBlock;
+ if (Result = wsDone) and not FEof then
+ begin
+ Result := wsPendingData;
+ PrepareChunk;
+ end;
+ end;
+end;
+
+function TBufferOutput.WriteBuffer: TWriteBlockStatus;
+begin
+ if not FOutputPending then
+ begin
+ Result := FillBuffer;
+ FEof := Result = wsDone;
+ FOutputPending := FEof;
+ if FOutputPending or (FBufferPos = FBufferSize) then
+ begin
+ if FBufferPos > FBufferOffset then
+ begin
+ FSocket.AddContentLength(FBufferPos-FBufferOffset);
+ if not FEof then
+ PrependBufferOutput(0)
+ else begin
+ FBufferSize := FBufferPos;
+ FBufferPos := FBufferOffset;
+ end;
+ end else begin
+ FBufferPos := 0;
+ FBufferSize := 0;
+ end;
+ if FEof then
+ FSocket.DoneBuffer(Self);
+ end;
+ end else
+ Result := EofToWriteStatus[FEof];
+ if Result = wsDone then
+ Result := inherited WriteBlock;
+end;
+
+function TBufferOutput.WritePlain: TWriteBlockStatus;
+begin
+ if not FOutputPending then
+ begin
+ Result := FillBuffer;
+ FEof := Result = wsDone;
+ if FBufferPos > FBufferOffset then
+ begin
+ FOutputPending := true;
+ FBufferSize := FBufferPos;
+ FBufferPos := FBufferOffset;
+ end else begin
+ FBufferSize := 0;
+ FBufferPos := 0;
+ end;
+ end;
+ Result := inherited WriteBlock;
+ if Result <> wsPendingData then
+ begin
+ PrepareBuffer;
+ if not FEof then
+ Result := wsPendingData;
+ end;
+end;
+
+function TBufferOutput.WriteBlock: TWriteBlockStatus;
+begin
+ Result := FWriteBlock();
+end;
+
+procedure TBufferOutput.SelectChunked;
+begin
+ FPrepareBuffer := @PrepareChunk;
+ FWriteBlock := @WriteChunk;
+ FFinishBuffer := @FinishChunk;
+ PrepareChunk;
+end;
+
+procedure TBufferOutput.SelectBuffered;
+begin
+ FPrepareBuffer := @PrepareBuffer;
+ FWriteBlock := @WriteBuffer;
+ FFinishBuffer := @FinishBuffer;
+ PrepareBuffer;
+end;
+
+procedure TBufferOutput.SelectPlain;
+begin
+ FPrepareBuffer := @PrepareBuffer;
+ FWriteBlock := @WritePlain;
+ FFinishBuffer := @FinishBuffer;
+ PrepareBuffer;
+end;
+
+{ TMemoryOutput }
+
+constructor TMemoryOutput.Create(ASocket: TLHTTPSocket; ABuffer: pointer;
+ ABufferOffset, ABufferSize: integer; AFreeBuffer: boolean);
+begin
+ inherited Create(ASocket);
+
+ FBuffer := ABuffer;
+ FBufferPos := ABufferOffset;
+ FBufferSize := ABufferSize;
+ FFreeBuffer := AFreeBuffer;
+ FOutputPending := true;
+end;
+
+destructor TMemoryOutput.Destroy;
+begin
+ inherited;
+ if FFreeBuffer then
+ FreeMem(FBuffer);
+end;
+
+{ TStreamOutput }
+
+constructor TStreamOutput.Create(ASocket: TLHTTPSocket; AStream: TStream; AFreeStream: boolean);
+begin
+ inherited Create(ASocket);
+ FStream := AStream;
+ FFreeStream := AFreeStream;
+ FStreamSize := AStream.Size;
+end;
+
+destructor TStreamOutput.Destroy;
+begin
+ if FFreeStream then
+ FStream.Free;
+ inherited;
+end;
+
+function TStreamOutput.FillBuffer: TWriteBlockStatus;
+var
+ lRead: integer;
+begin
+ lRead := FStream.Read(FBuffer[FBufferPos], FBufferSize-FBufferPos);
+ Inc(FBufferPos, lRead);
+ Result := BufferEmptyToWriteStatus[FStream.Position >= FStreamSize];
+end;
+
+{ TMemoryStreamOutput }
+
+constructor TMemoryStreamOutput.Create(ASocket: TLHTTPSocket; AStream: TMemoryStream;
+ AFreeStream: boolean);
+begin
+ inherited Create(ASocket);
+ FStream := AStream;
+ FFreeStream := AFreeStream;
+ FOutputPending := true;
+end;
+
+destructor TMemoryStreamOutput.Destroy;
+begin
+ if FFreeStream then
+ FStream.Free;
+ inherited;
+end;
+
+function TMemoryStreamOutput.WriteBlock: TWriteBlockStatus;
+var
+ lWritten: integer;
+begin
+ if not FOutputPending then
+ exit(wsDone);
+
+ lWritten := FSocket.Send(PByte(FStream.Memory)[FStream.Position], FStream.Size-FStream.Position);
+ FStream.Position := FStream.Position + lWritten;
+ FOutputPending := FStream.Position < FStream.Size;
+ FEof := not FOutputPending;
+ Result := EofToWriteStatus[FEof];
+end;
+
+{ TLHTTPSocket }
+
+constructor TLHTTPSocket.Create;
+begin
+ inherited;
+
+ FBuffer := GetMem(RequestBufferSize);
+ FBufferSize := RequestBufferSize;
+ FBufferPos := FBuffer;
+ FBufferEnd := FBufferPos;
+ FBuffer[0] := #0;
+ FKeepAlive := true;
+end;
+
+destructor TLHTTPSocket.Destroy;
+begin
+ FreeDelayFreeItems;
+ inherited;
+ FreeMem(FBuffer);
+end;
+
+procedure TLHTTPSocket.Disconnect;
+var
+ lOutput: TOutputItem;
+begin
+ inherited Disconnect;
+ while FCurrentOutput <> nil do
+ begin
+ lOutput := FCurrentOutput;
+ FCurrentOutput := FCurrentOutput.FNext;
+ lOutput.Free;
+ end;
+ if FCurrentInput <> nil then
+ FreeAndNil(FCurrentInput);
+end;
+
+procedure TLHTTPSocket.FreeDelayFreeItems;
+var
+ lItem: TOutputItem;
+begin
+ while FDelayFreeItems <> nil do
+ begin
+ lItem := FDelayFreeItems;
+ FDelayFreeItems := FDelayFreeItems.FNextDelayFree;
+ lItem.Free;
+ end;
+end;
+
+procedure TLHTTPSocket.DelayFree(AOutputItem: TOutputItem);
+begin
+ if AOutputItem = nil then exit;
+ if FDelayFreeItems <> nil then
+ FDelayFreeItems.FPrevDelayFree := AOutputItem;
+ AOutputItem.FNextDelayFree := FDelayFreeItems;
+ FDelayFreeItems := AOutputItem;
+end;
+
+procedure TLHTTPSocket.DoneBuffer(AOutput: TBufferOutput);
+begin
+end;
+
+procedure TLHTTPSocket.LogMessage;
+begin
+end;
+
+procedure TLHTTPSocket.LogAccess(const AMessage: string);
+begin
+end;
+
+procedure TLHTTPSocket.WriteError(AStatus: TLHTTPStatus);
+begin
+end;
+
+procedure TLHTTPSocket.AddToOutput(AOutputItem: TOutputItem);
+begin
+ AOutputItem.FPrev := FLastOutput;
+ if FLastOutput <> nil then
+ begin
+ FLastOutput.FNext := AOutputItem;
+ end else begin
+ FCurrentOutput := AOutputItem;
+ end;
+ FLastOutput := AOutputItem;
+end;
+
+procedure TLHTTPSocket.PrependOutput(ANewItem, AItem: TOutputItem);
+begin
+ ANewItem.FPrev := AItem.FPrev;
+ ANewItem.FNext := AItem;
+ AItem.FPrev := ANewItem;
+ if FCurrentOutput = AItem then
+ FCurrentOutput := ANewItem;
+end;
+
+procedure TLHTTPSocket.RemoveOutput(AOutputItem: TOutputItem);
+begin
+ if AOutputItem.FPrev <> nil then
+ AOutputItem.FPrev.FNext := AOutputItem.FNext;
+ if AOutputItem.FNext <> nil then
+ AOutputItem.FNext.FPrev := AOutputItem.FPrev;
+ if FLastOutput = AOutputItem then
+ FLastOutput := AOutputItem.FPrev;
+ if FCurrentOutput = AOutputItem then
+ FCurrentOutput := AOutputItem.FNext;
+ AOutputItem.FPrev := nil;
+ AOutputItem.FNext := nil;
+end;
+
+procedure TLHTTPSocket.ResetDefaults;
+begin
+ FParseBuffer := @ParseRequest;
+end;
+
+procedure TLHTTPSocket.FlushRequest;
+begin
+ FillDWord(FParameters, sizeof(FParameters) div 4, 0);
+ ResetDefaults;
+end;
+
+function TLHTTPSocket.CalcAvailableBufferSpace: integer;
+begin
+ Result := FBufferSize-(FBufferEnd-FBuffer)-1;
+end;
+
+procedure TLHTTPSocket.HandleReceive;
+var
+ lRead: integer;
+begin
+ if FRequestInputDone then
+ begin
+ IgnoreRead := true;
+ exit;
+ end;
+
+ lRead := CalcAvailableBufferSpace;
+ { if buffer has filled up, keep ignoring and continue parsing requests }
+ if lRead > 0 then
+ begin
+ IgnoreRead := false;
+ lRead := Get(FBufferEnd^, lRead);
+ if lRead = 0 then exit;
+ Inc(FBufferEnd, lRead);
+ FBufferEnd^ := #0;
+ end;
+ ParseBuffer;
+
+ if FIgnoreWrite then
+ WriteBlock;
+end;
+
+procedure TLHTTPSocket.RelocateVariable(var AVar: pchar);
+begin
+ if AVar = nil then exit;
+ AVar := FBuffer + (AVar - FRequestPos);
+end;
+
+procedure TLHTTPSocket.RelocateVariables;
+var
+ I: TLHTTPParameter;
+begin
+ for I := Low(TLHTTPParameter) to High(TLHTTPParameter) do
+ RelocateVariable(FParameters[I]);
+end;
+
+procedure TLHTTPSocket.PackRequestBuffer;
+var
+ lBytesLeft: integer;
+ lFreeBuffer: pchar;
+begin
+ if (FRequestBuffer <> nil) and (FBufferEnd-FBufferPos <= RequestBufferSize) then
+ begin
+ { switch back to normal size buffer }
+ lFreeBuffer := FBuffer;
+ FBuffer := FRequestBuffer;
+ FBufferSize := RequestBufferSize;
+ FRequestBuffer := nil;
+ end else
+ lFreeBuffer := nil;
+ if FRequestPos <> nil then
+ begin
+ lBytesLeft := FBufferEnd-FRequestPos;
+ FBufferEnd := FBuffer+lBytesLeft;
+ RelocateVariable(FBufferPos);
+ RelocateVariables;
+ { include null-terminator, where FBufferEnd is pointing at }
+ Move(FRequestPos^, FBuffer^, lBytesLeft+1);
+ FRequestPos := nil;
+ end;
+ if lFreeBuffer <> nil then
+ FreeMem(lFreeBuffer);
+end;
+
+procedure TLHTTPSocket.PackInputBuffer;
+var
+ lBytesLeft: integer;
+begin
+ { use bigger buffer for more speed }
+ if FRequestBuffer = nil then
+ begin
+ FRequestBuffer := FBuffer;
+ FBuffer := GetMem(DataBufferSize);
+ FBufferSize := DataBufferSize;
+ FRequestPos := nil;
+ end;
+ lBytesLeft := FBufferEnd-FBufferPos;
+ Move(FBufferPos^, FBuffer^, lBytesLeft);
+ FBufferEnd := FBuffer+lBytesLeft;
+ FBufferPos := FBuffer;
+end;
+
+function TLHTTPSocket.ParseEntityPlain: boolean;
+var
+ lNumBytes: integer;
+begin
+ lNumBytes := FBufferEnd - FBufferPos;
+ if lNumBytes > FInputRemaining then
+ lNumBytes := FInputRemaining;
+ { if no output item to feed into, discard }
+ if FCurrentInput <> nil then
+ lNumBytes := FCurrentInput.HandleInput(FBufferPos, lNumBytes);
+ inc(FBufferPos, lNumBytes);
+ dec(FInputRemaining, lNumBytes);
+ Result := FInputRemaining > 0;
+ { prepare for more data, if more data coming }
+ if Result and (FBufferPos+FInputRemaining > FBuffer+FBufferSize) then
+ PackInputBuffer;
+end;
+
+function TLHTTPSocket.ParseEntityChunked: boolean;
+var
+ lLineEnd, lNextLine: pchar;
+ lCode: integer;
+begin
+ repeat
+ if FChunkState = csFinished then
+ exit(false);
+ if FChunkState = csData then
+ if ParseEntityPlain then
+ exit(true)
+ else
+ FChunkState := csDataEnd;
+
+ lLineEnd := StrScan(FBufferPos, #10);
+ if lLineEnd = nil then
+ exit(true);
+
+ lNextLine := lLineEnd+1;
+ if (lLineEnd > FBufferPos) and ((lLineEnd-1)^ = #13) then
+ dec(lLineEnd);
+ case FChunkState of
+ csInitial:
+ begin
+ lLineEnd^ := #0;
+ HexToInt(FBufferPos, dword(FInputRemaining), lCode);
+ if lCode = 1 then
+ begin
+ FChunkState := csFinished;
+ Disconnect;
+ exit(false);
+ end;
+ if FInputRemaining = 0 then
+ FChunkState := csTrailer
+ else
+ FChunkState := csData;
+ end;
+ csDataEnd:
+ begin
+ { skip empty line }
+ FChunkState := csInitial;
+ end;
+ csTrailer:
+ begin
+ { trailer is optional, empty line indicates end }
+ if lLineEnd = FBufferPos then
+ FChunkState := csFinished
+ else
+ ParseParameterLine(lLineEnd);
+ end;
+ end;
+ FBufferPos := lNextLine;
+ until false;
+end;
+
+function TLHTTPSocket.ParseRequest: boolean;
+var
+ pNextLine, pLineEnd: pchar;
+begin
+ if FRequestHeaderDone then exit(not FRequestInputDone);
+ repeat
+ pLineEnd := StrScan(FBufferPos, #10);
+ if pLineEnd = nil then
+ begin
+ if (FRequestBuffer <> nil) or (FRequestPos <> nil) then
+ PackRequestBuffer
+ else if CalcAvailableBufferSpace = 0 then
+ WriteError(hsRequestTooLong);
+ exit(true);
+ end;
+
+ pNextLine := pLineEnd+1;
+ if (pLineEnd > FBufferPos) and ((pLineEnd-1)^ = #13) then
+ dec(pLineEnd);
+ pLineEnd^ := #0;
+ ParseLine(pLineEnd);
+ FBufferPos := pNextLine;
+ if FRequestHeaderDone then
+ exit(not FRequestInputDone);
+ until false;
+end;
+
+procedure TLHTTPSocket.ParseParameterLine(pLineEnd: pchar);
+var
+ lPos: pchar;
+ I: TLHTTPParameter;
+ lLen: integer;
+begin
+ lPos := StrScan(FBufferPos, ' ');
+ if (lPos = nil) or (lPos = FBufferPos) or ((lPos-1)^ <> ':') then
+ begin
+ WriteError(hsBadRequest);
+ exit;
+ end;
+
+ { null-terminate at colon }
+ (lPos-1)^ := #0;
+ StrUpper(FBufferPos);
+ lLen := lPos-FBufferPos-1;
+ for I := Low(TLHTTPParameter) to High(TLHTTPParameter) do
+ if (Length(HTTPParameterStrings[I]) = lLen)
+ and CompareMem(FBufferPos, PChar(HTTPParameterStrings[I]), lLen) then
+ begin
+ repeat
+ inc(lPos);
+ until lPos^ <> ' ';
+ FParameters[I] := lPos;
+ break;
+ end;
+end;
+
+procedure TLHTTPSocket.ParseLine(pLineEnd: pchar);
+begin
+ if FBufferPos[0] = #0 then
+ begin
+ FRequestHeaderDone := true;
+ ProcessHeaders;
+ end else
+ ParseParameterLine(pLineEnd);
+end;
+
+function TLHTTPSocket.ParseBuffer: boolean;
+var
+ lParseFunc: TParseBufferMethod;
+begin
+ repeat
+ lParseFunc := FParseBuffer;
+ Result := FParseBuffer();
+ if not Result and not FRequestInputDone then
+ begin
+ FRequestInputDone := true;
+ if FCurrentInput <> nil then
+ FCurrentInput.DoneInput;
+ end;
+ { if parse func changed mid-run, then we should continue calling the new
+ one: header + data }
+ until (lParseFunc = FParseBuffer) or not Result;
+end;
+
+function TLHTTPSocket.ProcessEncoding: boolean;
+var
+ lCode: integer;
+begin
+ Result := true;
+ if FParameters[hpContentLength] <> nil then
+ begin
+ FParseBuffer := @ParseEntityPlain;
+ Val(FParameters[hpContentLength], FInputRemaining, lCode);
+ if lCode <> 0 then
+ begin
+ WriteError(hsBadRequest);
+ exit;
+ end;
+ end else
+ if FParameters[hpTransferEncoding] <> nil then
+ begin
+ if (StrIComp(FParameters[hpTransferEncoding], 'chunked') = 0) then
+ begin
+ FParseBuffer := @ParseEntityChunked;
+ FChunkState := csInitial;
+ end else begin
+ Result := false;
+ end;
+ end else begin
+ FRequestInputDone := true;
+ end;
+end;
+
+function TLHTTPSocket.SetupEncoding(AOutputItem: TBufferOutput; AHeaderOut: PHeaderOutInfo): boolean;
+begin
+ if AHeaderOut^.ContentLength = 0 then
+ begin
+ if AHeaderOut^.Version >= 11 then
+ begin
+ { we can use chunked encoding }
+ AHeaderOut^.TransferEncoding := teChunked;
+ AOutputItem.SelectChunked;
+ end else begin
+ { we need to buffer the response to find its length }
+ AHeaderOut^.TransferEncoding := teIdentity;
+ AOutputItem.SelectBuffered;
+ { need to accumulate data before starting header output }
+ AddToOutput(AOutputItem);
+ exit(false);
+ end;
+ end else begin
+ AHeaderOut^.TransferEncoding := teIdentity;
+ AOutputItem.SelectPlain;
+ end;
+ Result := true;
+end;
+
+procedure TLHTTPSocket.WriteBlock;
+begin
+ while true do
+ begin
+ if FCurrentOutput = nil then
+ begin
+ if not FOutputDone or (not FRequestInputDone and FKeepAlive) then
+ break;
+
+ if not FKeepAlive then
+ begin
+ Disconnect;
+ exit;
+ end;
+
+ { next request }
+ FRequestInputDone := false;
+ FRequestHeaderDone := false;
+ FOutputDone := false;
+ FRequestPos := FBufferPos;
+ FlushRequest;
+ { rewind buffer pointers if at end of buffer anyway }
+ if FBufferPos = FBufferEnd then
+ PackRequestBuffer;
+
+ if ParseBuffer and IgnoreRead then
+ begin
+ { end of input buffer reached, try reading more }
+ HandleReceive;
+ end;
+
+ if FCurrentOutput = nil then
+ break;
+ end;
+
+ { if we cannot send, then the send buffer is full }
+ if not FCanSend or not FConnected then
+ break;
+
+ case FCurrentOutput.WriteBlock of
+ wsDone:
+ begin
+ if FCurrentOutput = FLastOutput then
+ FLastOutput := nil;
+ { some output items may trigger this parse/write loop }
+ DelayFree(FCurrentOutput);
+ FCurrentOutput := FCurrentOutput.FNext;
+ end;
+ wsWaitingData:
+ begin
+ { wait for more data from external source }
+ break;
+ end;
+ end;
+ { nothing left to write, request was busy and now completed }
+ if FCurrentOutput = nil then
+ begin
+ LogMessage;
+ FOutputDone := true;
+ end;
+ end;
+end;
+
+{ TLHTTPServerSocket }
+
+constructor TLHTTPServerSocket.Create;
+begin
+ inherited;
+
+ FLogMessage := InitStringBuffer(256);
+ FHeaderOut.ExtraHeaders := InitStringBuffer(256);
+ ResetDefaults;
+end;
+
+destructor TLHTTPServerSocket.Destroy;
+begin
+ FreeMem(FLogMessage.Memory);
+ FreeMem(FHeaderOut.ExtraHeaders.Memory);
+ inherited;
+end;
+
+procedure TLHTTPServerSocket.AddContentLength(ALength: integer);
+begin
+ Inc(FHeaderOut.ContentLength, ALength);
+end;
+
+procedure TLHTTPServerSocket.DoneBuffer(AOutput: TBufferOutput);
+begin
+ if FCurrentOutput <> AOutput then
+ begin
+ RemoveOutput(AOutput);
+ AOutput.FNext := FCurrentOutput;
+ FCurrentOutput := AOutput;
+ end;
+ WriteHeaders(AOutput, nil);
+end;
+
+procedure TLHTTPServerSocket.LogAccess(const AMessage: string);
+begin
+ TLHTTPConnection(FCreator).LogAccess(AMessage);
+end;
+
+procedure TLHTTPServerSocket.LogMessage;
+begin
+ { log a message about this request,
+ ' "" ""' }
+ AppendString(FLogMessage, IntToStr(HTTPStatusCodes[FResponseInfo.Status]));
+ AppendChar(FLogMessage, ' ');
+ AppendString(FLogMessage, IntToStr(FHeaderOut.ContentLength));
+ AppendString(FLogMessage, ' "');
+ AppendString(FLogMessage, FParameters[hpReferer]);
+ AppendString(FLogMessage, '" "');
+ AppendString(FLogMessage, FParameters[hpUserAgent]);
+ AppendChar(FLogMessage, '"');
+ AppendChar(FLogMessage, #0);
+ LogAccess(FLogMessage.Memory);
+end;
+
+procedure TLHTTPServerSocket.ResetDefaults;
+begin
+ inherited;
+ FRequestInfo.RequestType := hmUnknown;
+ FSetupEncodingState := seNone;
+ with FResponseInfo do
+ begin
+ Status := hsOK;
+ ContentType := 'application/octet-stream';
+ ContentCharset := '';
+ LastModified := 0.0;
+ end;
+end;
+
+procedure TLHTTPServerSocket.FlushRequest;
+ { reset structure to zero, not called from constructor }
+begin
+ with FRequestInfo do
+ begin
+ { request }
+ Argument := nil;
+ QueryParams := nil;
+ Version := 0;
+ end;
+ with FHeaderOut do
+ begin
+ ContentLength := 0;
+ TransferEncoding := teIdentity;
+ ExtraHeaders.Pos := ExtraHeaders.Memory;
+ Version := 0;
+ end;
+ inherited;
+end;
+
+procedure TLHTTPServerSocket.RelocateVariables;
+begin
+ RelocateVariable(FRequestInfo.Method);
+ RelocateVariable(FRequestInfo.Argument);
+ RelocateVariable(FRequestInfo.QueryParams);
+ RelocateVariable(FRequestInfo.VersionStr);
+ inherited;
+end;
+
+procedure TLHTTPServerSocket.ParseLine(pLineEnd: pchar);
+begin
+ if FRequestInfo.RequestType = hmUnknown then
+ begin
+ ParseRequestLine(pLineEnd);
+ exit;
+ end;
+
+ inherited;
+end;
+
+procedure TLHTTPServerSocket.ParseRequestLine(pLineEnd: pchar);
+var
+ lPos: pchar;
+ I: TLHTTPMethod;
+ NowLocal: TDateTime;
+begin
+ { make a timestamp for this request }
+ NowLocal := Now;
+ FRequestInfo.DateTime := LocalTimeToGMT(NowLocal);
+ { begin log message }
+ FLogMessage.Pos := FLogMessage.Memory;
+ AppendString(FLogMessage, PeerAddress);
+ AppendString(FLogMessage, ' - [');
+ AppendString(FLogMessage, FormatDateTime('dd/mmm/yyyy:hh:nn:ss', NowLocal));
+ AppendString(FLogMessage, TLHTTPServer(FCreator).FLogMessageTZString);
+ AppendString(FLogMessage, FBufferPos, pLineEnd-FBufferPos);
+ AppendString(FLogMessage, '" ');
+
+ { decode version }
+ lPos := pLineEnd;
+ repeat
+ if lPos^ = ' ' then break;
+ dec(lPos);
+ if lPos < FBufferPos then
+ begin
+ WriteError(hsBadRequest);
+ exit;
+ end;
+ until false;
+
+ lPos^ := #0;
+ inc(lPos);
+ { lPos = version string }
+ if not HTTPVersionCheck(lPos, pLineEnd, FRequestInfo.Version) then
+ begin
+ WriteError(hsBadRequest);
+ exit;
+ end;
+ FRequestInfo.VersionStr := lPos;
+ FHeaderOut.Version := FRequestInfo.Version;
+
+ { trim spaces at end of URI }
+ dec(lPos);
+ repeat
+ if lPos = FBufferPos then break;
+ dec(lPos);
+ if lPos^ <> ' ' then break;
+ lPos^ := #0;
+ until false;
+
+ { decode method }
+ FRequestInfo.Method := FBufferPos;
+ lPos := StrScan(FBufferPos, ' ');
+ if lPos = nil then
+ begin
+ WriteError(hsBadRequest);
+ exit;
+ end;
+
+ lPos^ := #0;
+ for I := Low(TLHTTPMethod) to High(TLHTTPMethod) do
+ begin
+ if I = hmUnknown then
+ begin
+ WriteError(hsNotImplemented);
+ exit;
+ end;
+
+ if ((lPos-FBufferPos) = Length(HTTPMethodStrings[I]))
+ and CompareMem(FBufferPos, PChar(HTTPMethodStrings[I]), lPos-FBufferPos) then
+ begin
+ repeat
+ inc(lPos);
+ until lPos^ <> ' ';
+ FRequestInfo.Argument := lPos;
+ FRequestInfo.RequestType := I;
+ break;
+ end;
+ end;
+
+ if ((pLineEnd-FRequestInfo.Argument) > 7) and (StrIComp(FRequestInfo.Argument, 'http://') = 0) then
+ begin
+ { absolute URI }
+ lPos := FRequestInfo.Argument+7;
+ while (lPos^ = '/') do
+ Inc(lPos);
+ FParameters[hpHost] := lPos;
+ lPos := StrScan(lPos, '/');
+ FRequestInfo.Argument := lPos;
+ end;
+ { FRequestInfo.Argument now points to an "abs_path" }
+ if FRequestInfo.Argument[0] <> '/' then
+ begin
+ WriteError(hsBadRequest);
+ exit;
+ end;
+ repeat
+ Inc(FRequestInfo.Argument);
+ until FRequestInfo.Argument[0] <> '/';
+end;
+
+procedure TLHTTPServerSocket.ProcessHeaders;
+ { process request }
+var
+ lPos: pchar;
+begin
+ { do HTTP/1.1 Host-field present check }
+ if (FRequestInfo.Version > 10) and (FParameters[hpHost] = nil) then
+ begin
+ WriteError(hsBadRequest);
+ exit;
+ end;
+
+ lPos := StrScan(FRequestInfo.Argument, '?');
+ if lPos <> nil then
+ begin
+ lPos^ := #0;
+ FRequestInfo.QueryParams := lPos+1;
+ end;
+
+ FKeepAlive := FRequestInfo.Version > 10;
+ if FParameters[hpConnection] <> nil then
+ begin
+ if StrIComp(FParameters[hpConnection], 'keep-alive') = 0 then
+ FKeepAlive := true
+ else
+ if StrIComp(FParameters[hpConnection], 'close') = 0 then
+ FKeepAlive := false;
+ end;
+
+ HTTPDecode(FRequestInfo.Argument);
+ if not CheckPermission(FRequestInfo.Argument) then
+ begin
+ WriteError(hsForbidden);
+ end else begin
+ if not ProcessEncoding then
+ begin
+ WriteError(hsNotImplemented);
+ exit;
+ end;
+
+ FCurrentInput := HandleURI;
+ { if we have a valid outputitem, wait until it is ready
+ to produce its response }
+ if FCurrentInput = nil then
+ begin
+ if FResponseInfo.Status = hsOK then
+ WriteError(hsNotFound)
+ else
+ WriteError(FResponseInfo.Status);
+ end else if FRequestInputDone then
+ FCurrentInput.DoneInput;
+ end;
+end;
+
+function TLHTTPServerSocket.PrepareResponse(AOutputItem: TOutputItem; ACustomErrorMessage: boolean): boolean;
+var
+ lDateTime: TDateTime;
+begin
+ { check modification date }
+ if FResponseInfo.Status < hsBadRequest then
+ begin
+ if (FParameters[hpIfModifiedSince] <> nil)
+ and (FResponseInfo.LastModified <> 0.0) then
+ begin
+ if TryHTTPDateStrToDateTime(FParameters[hpIfModifiedSince], lDateTime) then
+ begin
+ if lDateTime > FRequestInfo.DateTime then
+ FResponseInfo.Status := hsBadRequest
+ else
+ if FResponseInfo.LastModified <= lDateTime then
+ FResponseInfo.Status := hsNotModified;
+ end;
+ end else
+ if (FParameters[hpIfUnmodifiedSince] <> nil) then
+ begin
+ if TryHTTPDateStrToDateTime(FParameters[hpIfUnmodifiedSince], lDateTime) then
+ begin
+ if (FResponseInfo.LastModified = 0.0)
+ or (lDateTime < FResponseInfo.LastModified) then
+ FResponseInfo.Status := hsPreconditionFailed;
+ end;
+ end;
+ end;
+
+ if (FResponseInfo.Status < hsOK) or (FResponseInfo.Status in [hsNoContent, hsNotModified]) then
+ begin
+ { RFC says we MUST not include a response for these statuses }
+ ACustomErrorMessage := false;
+ FHeaderOut.ContentLength := 0;
+ end;
+
+ Result := (FResponseInfo.Status = hsOK) or ACustomErrorMessage;
+ if not Result then
+ begin
+ WriteError(FResponseInfo.Status);
+ DelayFree(AOutputItem);
+ end;
+end;
+
+procedure TLHTTPServerSocket.StartMemoryResponse(AOutputItem: TMemoryOutput; ACustomErrorMessage: boolean = false);
+begin
+ if PrepareResponse(AOutputItem, ACustomErrorMessage) then
+ begin
+ if FRequestInfo.RequestType <> hmHead then
+ FHeaderOut.ContentLength := AOutputItem.FBufferSize
+ else
+ FHeaderOut.ContentLength := 0;
+ WriteHeaders(nil, AOutputItem);
+ end;
+end;
+
+function TLHTTPServerSocket.SetupEncoding(AOutputItem: TBufferOutput): boolean;
+const
+ SetupEncodingToState: array[boolean] of TSetupEncodingState = (seWaitHeaders, seStartHeaders);
+begin
+ if FSetupEncodingState > seNone then
+ exit(FSetupEncodingState = seStartHeaders);
+ Result := inherited SetupEncoding(AOutputItem, @FHeaderOut);
+ FSetupEncodingState := SetupEncodingToState[Result];
+end;
+
+procedure TLHTTPServerSocket.StartResponse(AOutputItem: TBufferOutput; ACustomErrorMessage: boolean = false);
+begin
+ if PrepareResponse(AOutputItem, ACustomErrorMessage) then
+ if (FRequestInfo.RequestType = hmHead) or SetupEncoding(AOutputItem) then
+ WriteHeaders(nil, AOutputItem);
+end;
+
+function TLHTTPServerSocket.HandleURI: TOutputItem; {inline;} {<--- triggers IE}
+begin
+ Result := TLHTTPServer(FCreator).HandleURI(Self);
+end;
+
+procedure TLHTTPServerSocket.WriteError(AStatus: TLHTTPStatus);
+var
+ lMessage: string;
+ lMsgOutput: TMemoryOutput;
+begin
+ if AStatus in HTTPDisconnectStatuses then
+ FKeepAlive := false;
+ lMessage := HTTPDescriptions[AStatus];
+ FRequestHeaderDone := true;
+ FResponseInfo.Status := AStatus;
+ FHeaderOut.ContentLength := Length(lMessage);
+ FHeaderOut.TransferEncoding := teIdentity;
+ if Length(lMessage) > 0 then
+ begin
+ FResponseInfo.ContentType := 'text/html';
+ lMsgOutput := TMemoryOutput.Create(Self, PChar(lMessage), 0, Length(lMessage), false)
+ end else begin
+ FResponseInfo.ContentType := '';
+ lMsgOutput := nil;
+ end;
+ WriteHeaders(nil, lMsgOutput);
+end;
+
+procedure TLHTTPServerSocket.WriteHeaders(AHeaderResponse, ADataResponse: TOutputItem);
+var
+ lTemp: string[23];
+ lMessage: TStringBuffer;
+ tempStr: string;
+begin
+ lMessage := InitStringBuffer(504);
+
+ AppendString(lMessage, 'HTTP/1.1 ');
+ Str(HTTPStatusCodes[FResponseInfo.Status], lTemp);
+ AppendString(lMessage, lTemp);
+ AppendChar(lMessage, ' ');
+ AppendString(lMessage, HTTPTexts[FResponseInfo.Status]);
+ AppendString(lMessage, #13#10+'Date: ');
+ AppendString(lMessage, FormatDateTime(HTTPDateFormat, FRequestInfo.DateTime));
+ AppendString(lMessage, ' GMT');
+ tempStr := TLHTTPServer(FCreator).ServerSoftware;
+ if Length(tempStr) > 0 then
+ begin
+ AppendString(lMessage, #13#10+'Server: ');
+ AppendString(lMessage, tempStr);
+ end;
+ if Length(FResponseInfo.ContentType) > 0 then
+ begin
+ AppendString(lMessage, #13#10+'Content-Type: ');
+ AppendString(lMessage, FResponseInfo.ContentType);
+ if Length(FResponseInfo.ContentCharset) > 0 then
+ begin
+ AppendString(lMessage, '; charset=');
+ AppendString(lMessage, FResponseInfo.ContentCharset);
+ end;
+ end;
+ if FHeaderOut.TransferEncoding = teIdentity then
+ begin
+ AppendString(lMessage, #13#10+'Content-Length: ');
+ Str(FHeaderOut.ContentLength, lTemp);
+ AppendString(lMessage, lTemp);
+ end else begin
+ { only other possibility: teChunked }
+ AppendString(lMessage, #13#10+'Transfer-Encoding: chunked');
+ end;
+ if FResponseInfo.LastModified <> 0.0 then
+ begin
+ AppendString(lMessage, #13#10+'Last-Modified: ');
+ AppendString(lMessage, FormatDateTime(HTTPDateFormat, FResponseInfo.LastModified));
+ AppendString(lMessage, ' GMT');
+ end;
+ AppendString(lMessage, #13#10+'Connection: ');
+ if FKeepAlive then
+ AppendString(lMessage, 'keep-alive')
+ else
+ AppendString(lMessage, 'close');
+ AppendString(lMessage, #13#10);
+ with FHeaderOut.ExtraHeaders do
+ AppendString(lMessage, Memory, Pos-Memory);
+ AppendString(lMessage, #13#10);
+ if AHeaderResponse <> nil then
+ begin
+ AHeaderResponse.FBuffer := lMessage.Memory;
+ AHeaderResponse.FBufferSize := lMessage.Pos-lMessage.Memory;
+ end else
+ AddToOutput(TMemoryOutput.Create(Self, lMessage.Memory, 0,
+ lMessage.Pos-lMessage.Memory, true));
+
+ if ADataResponse <> nil then
+ begin
+ if FRequestInfo.RequestType = hmHead then
+ DelayFree(ADataResponse)
+ else
+ AddToOutput(ADataResponse);
+ end;
+end;
+
+{ TLHTTPConnection }
+
+destructor TLHTTPConnection.Destroy;
+begin
+ inherited;
+end;
+
+procedure TLHTTPConnection.LogAccess(const AMessage: string);
+begin
+end;
+
+procedure TLHTTPConnection.ReceiveEvent(aSocket: TLHandle);
+begin
+ TLHTTPSocket(aSocket).HandleReceive;
+ TLHTTPSocket(aSocket).FreeDelayFreeItems;
+end;
+
+procedure TLHTTPConnection.CanSendEvent(aSocket: TLHandle);
+begin
+ TLHTTPSocket(aSocket).WriteBlock;
+ TLHTTPSocket(aSocket).FreeDelayFreeItems;
+end;
+
+{ TLHTTPServer }
+
+constructor TLHTTPServer.Create(AOwner: TComponent);
+var
+ TZSign: char;
+ TZSecsAbs: integer;
+begin
+ inherited Create(AOwner);
+
+ SocketClass := TLHTTPServerSocket;
+ if TZSeconds >= 0 then
+ TZSign := '+'
+ else
+ TZSign := '-';
+ TZSecsAbs := Abs(TZSeconds);
+ FLogMessageTZString := Format(' %s%.2d%.2d] "',
+ [TZSign, TZSecsAbs div 3600, (TZSecsAbs div 60) mod 60]);
+end;
+
+function TLHTTPServer.HandleURI(ASocket: TLHTTPServerSocket): TOutputItem;
+var
+ lHandler: TURIHandler;
+begin
+ Result := nil;
+ lHandler := FHandlerList;
+ while lHandler <> nil do
+ begin
+ Result := lHandler.HandleURI(ASocket);
+ if ASocket.ResponseInfo.Status <> hsOK then break;
+ if Result <> nil then break;
+ lHandler := lHandler.FNext;
+ end;
+end;
+
+procedure TLHTTPServer.LogAccess(const AMessage: string);
+begin
+ if Assigned(FOnAccess) then
+ FOnAccess(AMessage);
+end;
+
+procedure TLHTTPServer.RegisterHandler(AHandler: TURIHandler);
+begin
+ if AHandler = nil then exit;
+ AHandler.FNext := FHandlerList;
+ FHandlerList := AHandler;
+ if Eventer <> nil then
+ AHandler.RegisterWithEventer(Eventer);
+end;
+
+procedure TLHTTPServer.RegisterWithEventer;
+var
+ lHandler: TURIHandler;
+begin
+ inherited;
+ lHandler := FHandlerList;
+ while lHandler <> nil do
+ begin
+ lHandler.RegisterWithEventer(Eventer);
+ lHandler := lHandler.FNext;
+ end;
+end;
+
+{ TClientInput }
+
+type
+ TClientOutput = class(TOutputItem)
+ protected
+ FPersistent: boolean;
+
+ procedure DoneInput; override;
+ public
+ constructor Create(ASocket: TLHTTPClientSocket);
+ destructor Destroy; override;
+ procedure FreeInstance; override;
+
+ function HandleInput(ABuffer: pchar; ASize: integer): integer; override;
+ function WriteBlock: TWriteBlockStatus; override;
+ end;
+
+constructor TClientOutput.Create(ASocket: TLHTTPClientSocket);
+begin
+ inherited Create(ASocket);
+ FPersistent := true;
+end;
+
+destructor TClientOutput.Destroy;
+begin
+ if FPersistent then exit;
+ inherited;
+end;
+
+procedure TClientOutput.FreeInstance;
+begin
+ if FPersistent then exit;
+ inherited;
+end;
+
+procedure TClientOutput.DoneInput;
+begin
+ TLHTTPClient(TLHTTPClientSocket(FSocket).FCreator).
+ DoDoneInput(TLHTTPClientSocket(FSocket));
+end;
+
+function TClientOutput.HandleInput(ABuffer: pchar; ASize: integer): integer;
+begin
+ Result := TLHTTPClient(TLHTTPClientSocket(FSocket).FCreator).
+ DoHandleInput(TLHTTPClientSocket(FSocket), ABuffer, ASize);
+end;
+
+function TClientOutput.WriteBlock: TWriteBlockStatus;
+begin
+ Result := TLHTTPClient(TLHTTPClientSocket(FSocket).FCreator).
+ DoWriteBlock(TLHTTPClientSocket(FSocket));
+end;
+
+{ TLHTTPClientSocket }
+
+constructor TLHTTPClientSocket.Create;
+begin
+ inherited Create;
+
+ FCurrentInput := TClientOutput.Create(Self);
+ ResetDefaults;
+end;
+
+destructor TLHTTPClientSocket.Destroy;
+begin
+ if Assigned(FCurrentInput) then begin
+ TClientOutput(FCurrentInput).FPersistent := false;
+ FreeAndNil(FCurrentInput);
+ end;
+ inherited;
+end;
+
+procedure TLHTTPClientSocket.AddContentLength(ALength: integer);
+begin
+ Inc(TLHTTPClient(FCreator).FHeaderOut.ContentLength, ALength);
+end;
+
+procedure TLHTTPClientSocket.Cancel(AError: TLHTTPClientError);
+begin
+ FError := AError;
+ Disconnect;
+end;
+
+function TLHTTPClientSocket.GetResponseReason: string;
+begin
+ Result := FResponse^.Reason;
+end;
+
+function TLHTTPClientSocket.GetResponseStatus: TLHTTPStatus;
+begin
+ Result := FResponse^.Status;
+end;
+
+procedure TLHTTPClientSocket.SendRequest;
+var
+ lMessage: TStringBuffer;
+ lTemp: string[23];
+ hasRangeStart, hasRangeEnd: boolean;
+begin
+ lMessage := InitStringBuffer(504);
+
+ AppendString(lMessage, HTTPMethodStrings[FRequest^.Method]);
+ AppendChar(lMessage, ' ');
+ AppendString(lMessage, FRequest^.URI);
+ AppendChar(lMessage, ' ');
+ AppendString(lMessage, 'HTTP/1.1'+#13#10+'Host: ');
+ AppendString(lMessage, TLHTTPClient(FCreator).Host);
+ if TLHTTPClient(FCreator).Port <> 80 then
+ begin
+ AppendChar(lMessage, ':');
+ Str(TLHTTPClient(FCreator).Port, lTemp);
+ AppendString(lMessage, lTemp);
+ end;
+ AppendString(lMessage, #13#10);
+ hasRangeStart := TLHTTPClient(FCreator).RangeStart <> high(qword);
+ hasRangeEnd := TLHTTPClient(FCreator).RangeEnd <> high(qword);
+ if hasRangeStart or hasRangeEnd then
+ begin
+ AppendString(lMessage, 'Range: bytes=');
+ if hasRangeStart then
+ begin
+ Str(TLHTTPClient(FCreator).RangeStart, lTemp);
+ AppendString(lMessage, lTemp);
+ end;
+ AppendChar(lMessage, '-');
+ if hasRangeEnd then
+ begin
+ Str(TLHTTPClient(FCreator).RangeEnd, lTemp);
+ AppendString(lMessage, lTemp);
+ end;
+ end;
+ with FHeaderOut^.ExtraHeaders do
+ AppendString(lMessage, Memory, Pos-Memory);
+ AppendString(lMessage, #13#10);
+ AddToOutput(TMemoryOutput.Create(Self, lMessage.Memory, 0,
+ lMessage.Pos-lMessage.Memory, true));
+ AddToOutput(FCurrentInput);
+
+ WriteBlock;
+end;
+
+procedure TLHTTPClientSocket.ParseLine(pLineEnd: pchar);
+begin
+ if FError <> ceNone then
+ exit;
+
+ if FResponse^.Status = hsUnknown then
+ begin
+ ParseStatusLine(pLineEnd);
+ exit;
+ end;
+
+ inherited;
+end;
+
+procedure TLHTTPClientSocket.ParseStatusLine(pLineEnd: pchar);
+var
+ lPos: pchar;
+begin
+ lPos := FBufferPos;
+ repeat
+ if lPos >= pLineEnd then
+ begin
+ Cancel(ceMalformedStatusLine);
+ exit;
+ end;
+ if lPos^ = ' ' then
+ break;
+ Inc(lPos);
+ until false;
+ if not HTTPVersionCheck(FBufferPos, lPos, FResponse^.Version) then
+ begin
+ Cancel(ceMalformedStatusLine);
+ exit;
+ end;
+
+ if (FResponse^.Version > 11) then
+ begin
+ Cancel(ceVersionNotSupported);
+ exit;
+ end;
+
+ { status code }
+ Inc(lPos);
+ if (lPos+3 >= pLineEnd) or (lPos[3] <> ' ') then
+ begin
+ Cancel(ceMalformedStatusLine);
+ exit;
+ end;
+ FResponse^.Status := CodeToHTTPStatus((ord(lPos[0])-ord('0'))*100
+ + (ord(lPos[1])-ord('0'))*10 + (ord(lPos[2])-ord('0')));
+ if FResponse^.Status = hsUnknown then
+ begin
+ Cancel(ceMalformedStatusLine);
+ exit;
+ end;
+
+ Inc(lPos, 4);
+ if lPos < pLineEnd then
+ FResponse^.Reason := lPos;
+end;
+
+procedure TLHTTPClientSocket.ProcessHeaders;
+begin
+ if not ProcessEncoding then
+ Cancel(ceUnsupportedEncoding);
+
+ TLHTTPClient(FCreator).DoProcessHeaders(Self);
+end;
+
+procedure TLHTTPClientSocket.ResetDefaults;
+begin
+ inherited;
+
+ FError := ceNone;
+end;
+
+{ TLHTTPClient }
+
+constructor TLHTTPClient.Create(AOwner: TComponent);
+begin
+ FPort:=80;
+ inherited;
+
+ SocketClass := TLHTTPClientSocket;
+ FRequest.Method := hmGet;
+ FHeaderOut.ExtraHeaders := InitStringBuffer(256);
+ ResetRange;
+end;
+
+destructor TLHTTPClient.Destroy;
+begin
+ FreeMem(FHeaderOut.ExtraHeaders.Memory);
+ inherited;
+end;
+
+procedure TLHTTPClient.AddExtraHeader(const AHeader: string);
+begin
+ AppendString(FHeaderOut.ExtraHeaders, AHeader);
+ AppendString(FHeaderOut.ExtraHeaders, #13#10);
+end;
+
+procedure TLHTTPClient.ConnectEvent(aSocket: TLHandle);
+begin
+ inherited;
+ InternalSendRequest;
+end;
+
+procedure TLHTTPClient.DoDoneInput(ASocket: TLHTTPClientSocket);
+begin
+ Dec(FPendingResponses);
+ if FPendingResponses = 0 then
+ FState := hcsIdle
+ else
+ FState := hcsWaiting;
+ if Assigned(FOnDoneInput) then
+ FOnDoneInput(ASocket);
+end;
+
+function TLHTTPClient.DoHandleInput(ASocket: TLHTTPClientSocket; ABuffer: pchar; ASize: integer): integer;
+begin
+ FState := hcsReceiving;
+ if Assigned(FOnInput) then
+ Result := FOnInput(ASocket, ABuffer, ASize)
+ else
+ Result := ASize;
+end;
+
+procedure TLHTTPClient.DoProcessHeaders(ASocket: TLHTTPClientSocket);
+begin
+ if Assigned(FOnProcessHeaders) then
+ FOnProcessHeaders(ASocket);
+end;
+
+function TLHTTPClient.DoWriteBlock(ASocket: TLHTTPClientSocket): TWriteBlockStatus;
+begin
+ Result := wsDone;
+ if not FOutputEof then
+ if Assigned(FOnCanWrite) then
+ FOnCanWrite(ASocket, Result)
+end;
+
+function TLHTTPClient.InitSocket(aSocket: TLSocket): TLSocket;
+begin
+ Result := inherited;
+ TLHTTPClientSocket(aSocket).FHeaderOut := @FHeaderOut;
+ TLHTTPClientSocket(aSocket).FRequest := @FRequest;
+ TLHTTPClientSocket(aSocket).FResponse := @FResponse;
+end;
+
+procedure TLHTTPClient.InternalSendRequest;
+begin
+ FOutputEof := false;
+ TLHTTPClientSocket(FIterator).SendRequest;
+ Inc(FPendingResponses);
+ if FState = hcsIdle then
+ FState := hcsWaiting;
+end;
+
+procedure TLHTTPClient.ResetRange;
+begin
+ FRequest.RangeStart := High(FRequest.RangeStart);
+ FRequest.RangeEnd := High(FRequest.RangeEnd);
+end;
+
+procedure TLHTTPClient.SendRequest;
+begin
+ if not Connected then
+ Connect(FHost, FPort)
+ else
+ InternalSendRequest;
+end;
+
+end.
+
diff --git a/utils/fppkg/lnet/lhttputil.pp b/utils/fppkg/lnet/lhttputil.pp
new file mode 100644
index 0000000000..1f7ba6f8c0
--- /dev/null
+++ b/utils/fppkg/lnet/lhttputil.pp
@@ -0,0 +1,232 @@
+{ Utility routines for HTTP server component
+
+ Copyright (C) 2006 Micha Nelissen
+
+ This library is Free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is diStributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+ for more details.
+
+ You should have received a Copy of the GNU Library General Public License
+ along with This library; if not, Write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ This license has been modified. See file LICENSE.ADDON for more information.
+ Should you find these sources without a LICENSE File, please contact
+ me at ales@chello.sk
+}
+
+unit lHTTPUtil;
+
+{$mode objfpc}{$h+}
+{$inline on}
+
+interface
+
+uses
+ sysutils,
+ strutils;
+
+const
+ HTTPDateFormat: string = 'ddd, dd mmm yyyy hh:nn:ss';
+ HTTPAllowedChars = ['A'..'Z','a'..'z', '*','@','.','_','-',
+ '0'..'9', '$','!','''','(',')'];
+
+type
+ PSearchRec = ^TSearchRec;
+
+ function GMTToLocalTime(ADateTime: TDateTime): TDateTime;
+ function LocalTimeToGMT(ADateTime: TDateTime): TDateTime;
+ function TryHTTPDateStrToDateTime(ADateStr: pchar; var ADest: TDateTime): boolean;
+
+ function SeparatePath(var InPath: string; out ExtraPath: string; const Mode:Longint;
+ ASearchRec: PSearchRec = nil): boolean;
+ function CheckPermission(const ADocument: pchar): boolean;
+ function HTTPDecode(AStr: pchar): pchar;
+ function HTTPEncode(const AStr: string): string;
+ function HexToNum(AChar: char): byte;
+
+implementation
+
+uses
+ lCommon;
+
+function GMTToLocalTime(ADateTime: TDateTime): TDateTime;
+begin
+ Result := ADateTime + (TZSeconds*1000/MSecsPerDay);
+end;
+
+function LocalTimeToGMT(ADateTime: TDateTime): TDateTime;
+begin
+ Result := ADateTime - (TZSeconds*1000/MSecsPerDay);
+end;
+
+function TryHTTPDateStrToDateTime(ADateStr: pchar; var ADest: TDateTime): boolean;
+var
+ lYear, lMonth, lDay: word;
+ lTime: array[0..2] of word;
+ I, lCode: integer;
+begin
+ if StrLen(ADateStr) < Length(HTTPDateFormat)+4 then exit(false);
+ { skip redundant short day string }
+ Inc(ADateStr, 5);
+ { day }
+ if ADateStr[2] = ' ' then
+ ADateStr[2] := #0
+ else
+ exit(false);
+ Val(ADateStr, lDay, lCode);
+ if lCode <> 0 then exit(false);
+ Inc(ADateStr, 3);
+ { month }
+ lMonth := 1;
+ repeat
+ if CompareMem(ADateStr, @ShortMonthNames[lMonth][1], 3) then break;
+ inc(lMonth);
+ if lMonth = 13 then exit(false);
+ until false;
+ Inc(ADateStr, 4);
+ { year }
+ if ADateStr[4] = ' ' then
+ ADateStr[4] := #0
+ else
+ exit(false);
+ Val(ADateStr, lYear, lCode);
+ if lCode <> 0 then exit(false);
+ Inc(ADateStr, 5);
+ { hour, minute, second }
+ for I := 0 to 2 do
+ begin
+ ADateStr[2] := #0;
+ Val(ADateStr, lTime[I], lCode);
+ Inc(ADateStr, 3);
+ if lCode <> 0 then exit(false);
+ end;
+ ADest := EncodeDate(lYear, lMonth, lDay) + EncodeTime(lTime[0], lTime[1], lTime[2], 0);
+ Result := true;
+end;
+
+function SeparatePath(var InPath: string; out ExtraPath: string; const Mode:Longint;
+ ASearchRec: PSearchRec = nil): boolean;
+var
+ lFullPath: string;
+ lPos: integer;
+ lSearchRec: TSearchRec;
+begin
+ if ASearchRec = nil then
+ ASearchRec := @lSearchRec;
+ ExtraPath := '';
+ if Length(InPath) <= 2 then exit(false);
+ lFullPath := InPath;
+ if InPath[Length(InPath)] = PathDelim then
+ SetLength(InPath, Length(InPath)-1);
+ repeat
+ Result := SysUtils.FindFirst(InPath, Mode, ASearchRec^) = 0;
+ SysUtils.FindClose(ASearchRec^);
+ if Result then
+ begin
+ ExtraPath := Copy(lFullPath, Length(InPath)+1, Length(lFullPath)-Length(InPath));
+ break;
+ end;
+ lPos := RPos(PathDelim, InPath);
+ if lPos > 0 then
+ SetLength(InPath, lPos-1)
+ else
+ break;
+ until false;
+end;
+
+function HexToNum(AChar: char): byte;
+begin
+ if ('0' <= AChar) and (AChar <= '9') then
+ Result := ord(AChar) - ord('0')
+ else if ('A' <= AChar) and (AChar <= 'F') then
+ Result := ord(AChar) - (ord('A') - 10)
+ else if ('a' <= AChar) and (AChar <= 'f') then
+ Result := ord(AChar) - (ord('a') - 10)
+ else
+ Result := 0;
+end;
+
+function HTTPDecode(AStr: pchar): pchar;
+var
+ lPos, lNext, lDest: pchar;
+begin
+ lDest := AStr;
+ repeat
+ lPos := AStr;
+ while not (lPos^ in ['%', '+', #0]) do
+ Inc(lPos);
+ if (lPos[0]='%') and (lPos[1] <> #0) and (lPos[2] <> #0) then
+ begin
+ lPos^ := char((HexToNum(lPos[1]) shl 4) + HexToNum(lPos[2]));
+ lNext := lPos+2;
+ end else if lPos[0] = '+' then
+ begin
+ lPos^ := ' ';
+ lNext := lPos+1;
+ end else
+ lNext := nil;
+ Inc(lPos);
+ if lDest <> AStr then
+ Move(AStr^, lDest^, lPos-AStr);
+ Inc(lDest, lPos-AStr);
+ AStr := lNext;
+ until lNext = nil;
+ Result := lDest;
+end;
+
+function HTTPEncode(const AStr: string): string;
+ { code from MvC's web }
+var
+ src, srcend, dest: pchar;
+ hex: string[2];
+ len: integer;
+begin
+ len := Length(AStr);
+ SetLength(Result, len*3); // Worst case scenario
+ if len = 0 then
+ exit;
+ dest := pchar(Result);
+ src := pchar(AStr);
+ srcend := src + len;
+ while src < srcend do
+ begin
+ if src^ in HTTPAllowedChars then
+ dest^ := src^
+ else if src^ = ' ' then
+ dest^ := '+'
+ else begin
+ dest^ := '%';
+ inc(dest);
+ hex := HexStr(Ord(src^),2);
+ dest^ := hex[1];
+ inc(dest);
+ dest^ := hex[2];
+ end;
+ inc(dest);
+ inc(src);
+ end;
+ SetLength(Result, dest - pchar(Result));
+end;
+
+function CheckPermission(const ADocument: pchar): boolean;
+var
+ lPos: pchar;
+begin
+ lPos := ADocument;
+ repeat
+ lPos := StrScan(lPos, '/');
+ if lPos = nil then exit(true);
+ if (lPos[1] = '.') and (lPos[2] = '.') and ((lPos[3] = '/') or (lPos[3] = #0)) then
+ exit(false);
+ inc(lPos);
+ until false;
+end;
+
+end.
diff --git a/utils/fppkg/lnet/lmimetypes.pp b/utils/fppkg/lnet/lmimetypes.pp
new file mode 100644
index 0000000000..191c967968
--- /dev/null
+++ b/utils/fppkg/lnet/lmimetypes.pp
@@ -0,0 +1,108 @@
+{ Mime types helper
+
+ Copyright (C) 2006 Micha Nelissen
+
+ This library is Free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is diStributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+ for more details.
+
+ You should have received a Copy of the GNU Library General Public License
+ along with This library; if not, Write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ This license has been modified. See file LICENSE.ADDON for more information.
+ Should you find these sources without a LICENSE File, please contact
+ me at ales@chello.sk
+}
+
+unit lMimeTypes;
+
+{$mode objfpc}{$h+}
+
+interface
+
+uses
+ classes, sysutils, strutils;
+
+type
+ TStringObject = class(TObject)
+ Str: string;
+ end;
+
+ procedure InitMimeList(const aFileName: string);
+
+var
+ MimeList: TStringList = nil;
+
+implementation
+
+var
+ MimeFileName: string;
+
+procedure InitMimeList(const aFileName: string);
+var
+ MimeFile: Text;
+ lPos, lNextPos: integer;
+ lLine, lName: string;
+ lStrObj: TStringObject;
+ lBuffer: array[1..32*1024] of byte;
+begin
+ if not Assigned(MimeList) then begin
+ MimeFileName := aFileName;
+ MimeList := TStringList.Create;
+ if FileExists(MimeFileName) then
+ begin
+ Assign(MimeFile, MimeFileName);
+ Reset(MimeFile);
+ SetTextBuf(MimeFile, lBuffer);
+ while not Eof(MimeFile) do
+ begin
+ ReadLn(MimeFile, lLine);
+ if (Length(lLine) = 0) or (lLine[1] = '#') then
+ continue;
+
+ lPos := Pos(#9, lLine);
+ if lPos = 0 then
+ continue;
+ lName := Copy(lLine, 1, lPos-1);
+
+ while (lPos <= Length(lLine)) and (lLine[lPos] in [#9,' ']) do
+ Inc(lPos);
+ if lPos > Length(lLine) then
+ continue;
+ repeat
+ lNextPos := PosEx(' ', lLine, lPos);
+ if lNextPos = 0 then
+ lNextPos := Length(lLine)+1;
+ lStrObj := TStringObject.Create;
+ lStrObj.Str := lName;
+ MimeList.AddObject('.'+Copy(lLine, lPos, lNextPos-lPos), lStrObj);
+ lPos := lNextPos+1;
+ until lPos > Length(lLine);
+ end;
+ close(MimeFile);
+ end;
+ MimeList.Sorted := true;
+ end;
+end;
+
+procedure FreeMimeList;
+var
+ I: integer;
+begin
+ if Assigned(MimeList) then begin
+ for I := 0 to MimeList.Count - 1 do
+ MimeList.Objects[I].Free;
+ FreeAndNil(MimeList);
+ end;
+end;
+
+finalization
+ FreeMimeList;
+end.
diff --git a/utils/fppkg/lnet/lnet.pp b/utils/fppkg/lnet/lnet.pp
index 0b97318bfe..3525313987 100644
--- a/utils/fppkg/lnet/lnet.pp
+++ b/utils/fppkg/lnet/lnet.pp
@@ -440,7 +440,7 @@ procedure TLSocket.LogError(const msg: string; const ernum: Integer);
begin
if Assigned(FOnError) then
if ernum > 0 then
- FOnError(Self, msg + ': ' + LStrError(ernum))
+ FOnError(Self, msg + '[' + IntToStr(ernum) + ']: ' + LStrError(ernum))
else
FOnError(Self, msg);
end;
diff --git a/utils/fppkg/lnet/lprocess.pp b/utils/fppkg/lnet/lprocess.pp
new file mode 100644
index 0000000000..87ba9075cc
--- /dev/null
+++ b/utils/fppkg/lnet/lprocess.pp
@@ -0,0 +1,185 @@
+{ Asynchronous process support
+
+ Copyright (C) 2006 Micha Nelissen
+
+ This library is Free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is diStributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+ for more details.
+
+ You should have received a Copy of the GNU Library General Public License
+ along with This library; if not, Write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ This license has been modified. See file LICENSE.ADDON for more information.
+ Should you find these sources without a LICENSE File, please contact
+ me at ales@chello.sk
+}
+
+unit lProcess;
+
+{$mode objfpc}{$h+}
+
+interface
+
+uses
+ sysutils, classes, process, levents, pipes;
+
+type
+ TLInputPipeStream = class(TInputPipeStream)
+ protected
+ FEvent: TLHandle;
+ public
+ function Read(var Buffer; Count: longint): longint; override;
+ end;
+
+ TLOutputPipeStream = class(TOutputPipeStream)
+ protected
+ FEvent: TLHandle;
+ public
+ function Write(const Buffer; Count: longint): longint; override;
+ end;
+
+ TLProcess = class(TProcess)
+ protected
+ FInputEvent: TLHandle;
+ FOutputEvent: TLHandle;
+ FStderrEvent: TLHandle;
+ FEventer: TLEventer;
+
+ function GetOnNeedInput: TLHandleEvent;
+ function GetOnHasOutput: TLHandleEvent;
+ function GetOnHasStderr: TLHandleEvent;
+ procedure SetOnNeedInput(NewOnInput: TLHandleEvent);
+ procedure SetOnHasOutput(NewOnOutput: TLHandleEvent);
+ procedure SetOnHasStderr(NewOnStderr: TLHandleEvent);
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+
+ procedure CloseInput; override;
+ procedure CloseOutput; override;
+ procedure CloseStderr; override;
+ procedure Execute; override;
+
+ property InputEvent: TLHandle read FInputEvent;
+ property OutputEvent: TLHandle read FOutputEvent;
+ property StderrEvent: TLHandle read FStderrEvent;
+ property Eventer: TLEventer read FEventer write FEventer;
+ property OnNeedInput: TLHandleEvent read GetOnNeedInput write SetOnNeedInput;
+ property OnHasOutput: TLHandleEvent read GetOnHasOutput write SetOnHasOutput;
+ property OnHasStderr: TLHandleEvent read GetOnHasStderr write SetOnHasStderr;
+ end;
+
+implementation
+
+function TLInputPipeStream.Read(var Buffer; Count: longint): longint;
+begin
+ Result := inherited;
+ FEvent.IgnoreRead := false;
+end;
+
+function TLOutputPipeStream.Write(const Buffer; Count: longint): longint;
+begin
+ Result := inherited;
+ FEvent.IgnoreWrite := false;
+end;
+
+constructor TLProcess.Create(AOwner: TComponent);
+begin
+ inherited;
+
+ FInputEvent := TLHandle.Create;
+ FOutputEvent := TLHandle.Create;
+ FStderrEvent := TLHandle.Create;
+end;
+
+destructor TLProcess.Destroy;
+begin
+ inherited;
+ FInputEvent.Free;
+ FOutputEvent.Free;
+ FStderrEvent.Free;
+end;
+
+procedure TLProcess.CloseInput;
+begin
+ FEventer.UnplugHandle(FInputEvent);
+ inherited;
+end;
+
+procedure TLProcess.CloseOutput;
+begin
+ FEventer.UnplugHandle(FOutputEvent);
+ inherited;
+end;
+
+procedure TLProcess.CloseStderr;
+begin
+ FEventer.UnplugHandle(FStderrEvent);
+ inherited;
+end;
+
+procedure TLProcess.Execute;
+begin
+ inherited;
+
+ if (poUsePipes in Options) and (FEventer <> nil) then
+ begin
+ if Input <> nil then
+ begin
+ FInputEvent.Handle := Input.Handle;
+ FInputEvent.IgnoreRead := true;
+ FEventer.AddHandle(FInputEvent);
+ end;
+ if Output <> nil then
+ begin
+ FOutputEvent.Handle := Output.Handle;
+ FOutputEvent.IgnoreWrite := true;
+ FEventer.AddHandle(FOutputEvent);
+ end;
+ if Stderr <> nil then
+ begin
+ FStderrEvent.Handle := Stderr.Handle;
+ FStderrEvent.IgnoreWrite := true;
+ FEventer.AddHandle(FStderrEvent);
+ end;
+ end;
+end;
+
+function TLProcess.GetOnNeedInput: TLHandleEvent;
+begin
+ Result := FInputEvent.OnWrite;
+end;
+
+function TLProcess.GetOnHasOutput: TLHandleEvent;
+begin
+ Result := FOutputEvent.OnRead;
+end;
+
+function TLProcess.GetOnHasStderr: TLHandleEvent;
+begin
+ Result := FStderrEvent.OnRead;
+end;
+
+procedure TLProcess.SetOnNeedInput(NewOnInput: TLHandleEvent);
+begin
+ FInputEvent.OnWrite := NewOnInput;
+end;
+
+procedure TLProcess.SetOnHasOutput(NewOnOutput: TLHandleEvent);
+begin
+ FOutputEvent.OnRead := NewOnOutput;
+end;
+
+procedure TLProcess.SetOnHasStderr(NewOnStderr: TLHandleEvent);
+begin
+ FStderrEvent.OnRead := NewOnStderr;
+end;
+
+end.
diff --git a/utils/fppkg/lnet/lsmtp.pp b/utils/fppkg/lnet/lsmtp.pp
new file mode 100644
index 0000000000..adeadedf4e
--- /dev/null
+++ b/utils/fppkg/lnet/lsmtp.pp
@@ -0,0 +1,530 @@
+{ lNet SMTP unit
+
+ CopyRight (C) 2005-2006 Ales Katona
+
+ This library is Free software; you can rediStribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is diStributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+ for more details.
+
+ You should have received a Copy of the GNU Library General Public License
+ along with This library; if not, Write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ This license has been modified. See File LICENSE.ADDON for more inFormation.
+ Should you find these sources without a LICENSE File, please contact
+ me at ales@chello.sk
+}
+
+unit lsmtp;
+
+{$mode objfpc}{$H+}
+{$inline on}
+
+interface
+
+uses
+ Classes, lNet, lEvents, lCommon;
+
+type
+ TLSMTP = class;
+ TLSMTPClient = class;
+
+ TLSMTPStatus = (ssNone, ssCon, ssHelo, ssEhlo, ssMail,
+ ssRcpt, ssData, ssRset, ssQuit);
+
+ TLSMTPStatusSet = set of TLSMTPStatus;
+
+ TLSMTPStatusRec = record
+ Status: TLSMTPStatus;
+ Args: array[1..2] of string;
+ end;
+
+ { TLSMTPStatusFront }
+ {$DEFINE __front_type__ := TLSMTPStatusRec}
+ {$i lcontainersh.inc}
+ TLSMTPStatusFront = TLFront;
+
+ TLSMTPClientStatusEvent = procedure (aSocket: TLSocket;
+ const aStatus: TLSMTPStatus) of object;
+
+ TLSMTP = class(TLComponent)
+ protected
+ FConnection: TLTcp;
+ protected
+ function GetTimeout: DWord;
+ procedure SetTimeout(const AValue: DWord);
+
+ function GetConnected: Boolean;
+
+ function GetSocketClass: TLSocketClass;
+ procedure SetSocketClass(const AValue: TLSocketClass);
+
+ function GetEventer: TLEventer;
+ procedure SetEventer(Value: TLEventer);
+ public
+ constructor Create(aOwner: TComponent); override;
+ destructor Destroy; override;
+ public
+ property Connected: Boolean read GetConnected;
+ property Connection: TLTcp read FConnection;
+
+ property SocketClass: TLSocketClass read GetSocketClass write SetSocketClass;
+ property Eventer: TLEventer read GetEventer write SetEventer;
+ property Timeout: DWord read GetTimeout write SetTimeout;
+ end;
+
+ { TLSMTPClient }
+
+ TLSMTPClient = class(TLSMTP, ILClient)
+ protected
+ FStatus: TLSMTPStatusFront;
+ FCommandFront: TLSMTPStatusFront;
+ FPipeLine: Boolean;
+
+ FOnConnect: TLSocketEvent;
+ FOnReceive: TLSocketEvent;
+ FOnDisconnect: TLSocketEvent;
+ FOnSuccess: TLSMTPClientStatusEvent;
+ FOnFailure: TLSMTPClientStatusEvent;
+ FOnError: TLSocketErrorEvent;
+
+ FSL: TStringList;
+ FStatusSet: TLSMTPStatusSet;
+ FMessage: string;
+ protected
+ procedure OnEr(const msg: string; aSocket: TLSocket);
+ procedure OnRe(aSocket: TLSocket);
+ procedure OnCo(aSocket: TLSocket);
+ procedure OnDs(aSocket: TLSocket);
+ protected
+ function CanContinue(const aStatus: TLSMTPStatus; const Arg1, Arg2: string): Boolean;
+
+ function CleanInput(var s: string): Integer;
+
+ procedure EvaluateAnswer(const Ans: string);
+
+ procedure ExecuteFrontCommand;
+ public
+ constructor Create(aOwner: TComponent); override;
+ destructor Destroy; override;
+
+ function Connect(const aHost: string; const aPort: Word = 25): Boolean; virtual;
+ function Connect: Boolean; virtual;
+
+ function Get(var aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; virtual;
+ function GetMessage(out msg: string; aSocket: TLSocket = nil): Integer; virtual;
+
+ procedure SendMail(const From, Recipients, Subject, Msg: string);
+ procedure Helo(aHost: string = '');
+ procedure Ehlo(aHost: string = '');
+ procedure Mail(const From: string);
+ procedure Rcpt(const RcptTo: string);
+ procedure Data(const Msg: string);
+ procedure Rset;
+ procedure Quit;
+
+ procedure Disconnect; override;
+
+ procedure CallAction; override;
+ public
+ property PipeLine: Boolean read FPipeLine write FPipeLine;
+ property StatusSet: TLSMTPStatusSet read FStatusSet write FStatusSet;
+ property OnConnect: TLSocketEvent read FOnConnect write FOnConnect;
+ property OnReceive: TLSocketEvent read FOnReceive write FOnReceive;
+ property OnDisconnect: TLSocketEvent read FOnDisconnect write FOnDisconnect;
+ property OnSuccess: TLSMTPClientStatusEvent read FOnSuccess write FOnSuccess;
+ property OnFailure: TLSMTPClientStatusEvent read FOnFailure write FOnFailure;
+ property OnError: TLSocketErrorEvent read FOnError write FOnError;
+ end;
+
+implementation
+
+uses
+ SysUtils;
+
+const
+ EMPTY_REC: TLSMTPStatusRec = (Status: ssNone; Args: ('', ''));
+ SLE = #13#10;
+
+{$i lcontainers.inc}
+
+function StatusToStr(const aStatus: TLSMTPStatus): string;
+const
+ STATAR: array[ssNone..ssQuit] of string = ('ssNone', 'ssCon', 'ssHelo', 'ssEhlo', 'ssMail',
+ 'ssRcpt', 'ssData', 'ssRset', 'ssQuit');
+begin
+ Result := STATAR[aStatus];
+end;
+
+function MakeStatusRec(const aStatus: TLSMTPStatus; const Arg1, Arg2: string): TLSMTPStatusRec;
+begin
+ Result.Status := aStatus;
+ Result.Args[1] := Arg1;
+ Result.Args[2] := Arg2;
+end;
+
+{ TLSMTP }
+
+function TLSMTP.GetTimeout: DWord;
+begin
+ Result := FConnection.Timeout;
+end;
+
+procedure TLSMTP.SetTimeout(const AValue: DWord);
+begin
+ FConnection.Timeout := aValue;
+end;
+
+function TLSMTP.GetConnected: Boolean;
+begin
+ Result := FConnection.Connected;
+end;
+
+function TLSMTP.GetSocketClass: TLSocketClass;
+begin
+ Result := FConnection.SocketClass;
+end;
+
+procedure TLSMTP.SetSocketClass(const AValue: TLSocketClass);
+begin
+ FConnection.SocketClass := AValue;
+end;
+
+function TLSMTP.GetEventer: TLEventer;
+begin
+ Result := FConnection.Eventer;
+end;
+
+procedure TLSMTP.SetEventer(Value: TLEventer);
+begin
+ FConnection.Eventer := Value;
+end;
+
+constructor TLSMTP.Create(aOwner: TComponent);
+begin
+ inherited Create(aOwner);
+
+ FConnection := TLTcp.Create(nil);
+end;
+
+destructor TLSMTP.Destroy;
+begin
+ FConnection.Free;
+
+ inherited Destroy;
+end;
+
+{ TLSMTPClient }
+
+constructor TLSMTPClient.Create(aOwner: TComponent);
+begin
+ inherited Create(aOwner);
+ FPort := 25;
+ FStatusSet := []; // empty set for "ok/not-ok" Event
+ FSL := TStringList.Create;
+ FHost := '';
+ FMessage := '';
+// {$warning TODO: fix pipelining support when server does it}
+ FPipeLine := False;
+
+ FConnection.OnError := @OnEr;
+ FConnection.OnReceive := @OnRe;
+ FConnection.OnConnect := @OnCo;
+
+ FStatus := TLSMTPStatusFront.Create(EMPTY_REC);
+ FCommandFront := TLSMTPStatusFront.Create(EMPTY_REC);
+end;
+
+destructor TLSMTPClient.Destroy;
+begin
+ Quit;
+ FSL.Free;
+ FStatus.Free;
+ FCommandFront.Free;
+
+ inherited Destroy;
+end;
+
+procedure TLSMTPClient.OnEr(const msg: string; aSocket: TLSocket);
+begin
+ if Assigned(FOnError) then
+ FOnError(msg, aSocket);
+end;
+
+procedure TLSMTPClient.OnRe(aSocket: TLSocket);
+begin
+ if Assigned(FOnReceive) then
+ FOnReceive(aSocket);
+end;
+
+procedure TLSMTPClient.OnCo(aSocket: TLSocket);
+begin
+ if Assigned(FOnConnect) then
+ FOnConnect(aSocket);
+end;
+
+procedure TLSMTPClient.OnDs(aSocket: TLSocket);
+begin
+ if Assigned(FOnDisconnect) then
+ FOnDisconnect(aSocket);
+end;
+
+function TLSMTPClient.CanContinue(const aStatus: TLSMTPStatus; const Arg1, Arg2: string): Boolean;
+begin
+ Result := FPipeLine or FStatus.Empty;
+ if not Result then
+ FCommandFront.Insert(MakeStatusRec(aStatus, Arg1, Arg2));
+end;
+
+function TLSMTPClient.CleanInput(var s: string): Integer;
+var
+ i: Integer;
+begin
+ FSL.Text := s;
+ if FSL.Count > 0 then
+ for i := 0 to FSL.Count-1 do
+ if Length(FSL[i]) > 0 then EvaluateAnswer(FSL[i]);
+ s := StringReplace(s, SLE, LineEnding, [rfReplaceAll]);
+ i := Pos('PASS', s);
+ if i > 0 then
+ s := Copy(s, 1, i-1) + 'PASS';
+ Result := Length(s);
+end;
+
+procedure TLSMTPClient.EvaluateAnswer(const Ans: string);
+
+ function GetNum: Integer;
+ begin
+ try
+ Result := StrToInt(Copy(Ans, 1, 3));
+ except
+ Result := -1;
+ end;
+ end;
+
+ function ValidResponse(const Answer: string): Boolean; inline;
+ begin
+ Result := (Length(Ans) >= 3) and
+ (Ans[1] in ['1'..'5']) and
+ (Ans[2] in ['0'..'9']) and
+ (Ans[3] in ['0'..'9']);
+
+ if Result then
+ Result := (Length(Ans) = 3) or ((Length(Ans) > 3) and (Ans[4] = ' '));
+ end;
+
+ procedure Eventize(const aStatus: TLSMTPStatus; const Res: Boolean);
+ begin
+ if Res then begin
+ if Assigned(FOnSuccess) and (aStatus in FStatusSet) then
+ FOnSuccess(FConnection.Iterator, aStatus);
+ end else begin
+ if Assigned(FOnFailure) and (aStatus in FStatusSet) then
+ FOnFailure(FConnection.Iterator, aStatus);
+ end;
+ end;
+
+var
+ x: Integer;
+begin
+ x := GetNum;
+ if ValidResponse(Ans) and not FStatus.Empty then
+ case FStatus.First.Status of
+ ssCon,
+ ssHelo,
+ ssEhlo: case x of
+ 200..299: begin
+ Eventize(FStatus.First.Status, True);
+ FStatus.Remove;
+ end;
+ else begin
+ Eventize(FStatus.First.Status, False);
+ Disconnect;
+ end;
+ end;
+
+ ssMail,
+ ssRcpt: begin
+ Eventize(FStatus.First.Status, (x >= 200) and (x < 299));
+ FStatus.Remove;
+ end;
+
+ ssData: case x of
+ 200..299: begin
+ Eventize(FStatus.First.Status, True);
+ FStatus.Remove;
+ end;
+ 300..399: if Length(FMessage) > 0 then begin
+ FConnection.SendMessage(FMessage);
+ FMessage := '';
+ end;
+ else begin
+ Eventize(FStatus.First.Status, False);
+ FStatus.Remove;
+ end;
+ end;
+
+ ssRset: begin
+ Eventize(FStatus.First.Status, (x >= 200) and (x < 299));
+ FStatus.Remove;
+ end;
+
+ ssQuit: begin
+ Eventize(FStatus.First.Status, (x >= 200) and (x < 299));
+ FStatus.Remove;
+ if Assigned(FOnDisconnect) then
+ FOnDisconnect(FConnection.Iterator);
+ Disconnect;
+ end;
+ end;
+ if FStatus.Empty and not FCommandFront.Empty then
+ ExecuteFrontCommand;
+end;
+
+procedure TLSMTPClient.ExecuteFrontCommand;
+begin
+ with FCommandFront.First do
+ case Status of
+ ssHelo: Helo(Args[1]);
+ ssEhlo: Ehlo(Args[1]);
+ ssMail: Mail(Args[1]);
+ ssRcpt: Rcpt(Args[1]);
+ ssData: Data(Args[1]);
+ ssRset: Rset;
+ ssQuit: Quit;
+ end;
+ FCommandFront.Remove;
+end;
+
+function TLSMTPClient.Connect(const aHost: string; const aPort: Word = 25): Boolean;
+begin
+ Result := False;
+ Disconnect;
+ if FConnection.Connect(aHost, aPort) then begin
+ FHost := aHost;
+ FPort := aPort;
+ FStatus.Insert(MakeStatusRec(ssCon, '', ''));
+ Result := True;
+ end;
+end;
+
+function TLSMTPClient.Connect: Boolean;
+begin
+ Result := Connect(FHost, FPort);
+end;
+
+function TLSMTPClient.Get(var aData; const aSize: Integer; aSocket: TLSocket): Integer;
+var
+ s: string;
+begin
+ Result := FConnection.Get(aData, aSize, aSocket);
+ if Result > 0 then begin
+ SetLength(s, Result);
+ Move(aData, PChar(s)^, Result);
+ CleanInput(s);
+ end;
+end;
+
+function TLSMTPClient.GetMessage(out msg: string; aSocket: TLSocket): Integer;
+begin
+ Result := FConnection.GetMessage(msg, aSocket);
+ if Result > 0 then
+ Result := CleanInput(msg);
+end;
+
+procedure TLSMTPClient.SendMail(const From, Recipients, Subject, Msg: string);
+var
+ i: Integer;
+begin
+ if (Length(Recipients) > 0) and (Length(From) > 0) then begin
+ Mail(From);
+ FSL.CommaText := StringReplace(Recipients, ' ', ',', [rfReplaceAll]);
+ for i := 0 to FSL.Count-1 do
+ Rcpt(FSL[i]);
+ Data('From: ' + From + SLE + 'Subject: ' + Subject + SLE + 'To: ' + FSL.CommaText + SLE + Msg);
+ Rset;
+ end;
+end;
+
+procedure TLSMTPClient.Helo(aHost: string = '');
+begin
+ if Length(Host) = 0 then
+ aHost := FHost;
+ if CanContinue(ssHelo, aHost, '') then begin
+ FConnection.SendMessage('HELO ' + aHost + SLE);
+ FStatus.Insert(MakeStatusRec(ssHelo, '', ''));
+ end;
+end;
+
+procedure TLSMTPClient.Ehlo(aHost: string = '');
+begin
+ if Length(aHost) = 0 then
+ aHost := FHost;
+ if CanContinue(ssEhlo, aHost, '') then begin
+ FConnection.SendMessage('EHLO ' + aHost + SLE);
+ FStatus.Insert(MakeStatusRec(ssEhlo, '', ''));
+ end;
+end;
+
+procedure TLSMTPClient.Mail(const From: string);
+begin
+ if CanContinue(ssMail, From, '') then begin
+ FConnection.SendMessage('MAIL FROM:' + '<' + From + '>' + SLE);
+ FStatus.Insert(MakeStatusRec(ssMail, '', ''));
+ end;
+end;
+
+procedure TLSMTPClient.Rcpt(const RcptTo: string);
+begin
+ if CanContinue(ssRcpt, RcptTo, '') then begin
+ FConnection.SendMessage('RCPT TO:' + '<' + RcptTo + '>' + SLE);
+ FStatus.Insert(MakeStatusRec(ssRcpt, '', ''));
+ end;
+end;
+
+procedure TLSMTPClient.Data(const Msg: string);
+begin
+ if CanContinue(ssData, Msg, '') then begin
+ // TODO: clean SLEs and '.' on line starts
+ FMessage := Msg + SLE + '.' + SLE;
+ FConnection.SendMessage('DATA' + SLE);
+ FStatus.Insert(MakeStatusRec(ssData, '', ''));
+ end;
+end;
+
+procedure TLSMTPClient.Rset;
+begin
+ if CanContinue(ssRset, '', '') then begin
+ FConnection.SendMessage('RSET' + SLE);
+ FStatus.Insert(MakeStatusRec(ssRset, '', ''));
+ end;
+end;
+
+procedure TLSMTPClient.Quit;
+begin
+ if CanContinue(ssQuit, '', '') then begin
+ FConnection.SendMessage('QUIT' + SLE);
+ FStatus.Insert(MakeStatusRec(ssQuit, '', ''));
+ end;
+end;
+
+procedure TLSMTPClient.Disconnect;
+begin
+ FConnection.Disconnect;
+ FStatus.Clear;
+ FCommandFront.Clear;
+end;
+
+procedure TLSMTPClient.CallAction;
+begin
+ FConnection.CallAction;
+end;
+
+end.
+
diff --git a/utils/fppkg/lnet/lspawnfcgi.pp b/utils/fppkg/lnet/lspawnfcgi.pp
new file mode 100644
index 0000000000..280ad94c7f
--- /dev/null
+++ b/utils/fppkg/lnet/lspawnfcgi.pp
@@ -0,0 +1,21 @@
+unit lSpawnFCGI;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Sockets, lNet, lCommon;
+
+ function SpawnFCGIProcess(App, Enviro: string; const aPort: Word): Integer;
+
+implementation
+
+{$ifdef UNIX}
+ {$i lspawnfcgiunix.inc}
+{$else}
+ {$i lspawnfcgiwin.inc}
+{$endif}
+
+end.
+
diff --git a/utils/fppkg/lnet/ltimer.pp b/utils/fppkg/lnet/ltimer.pp
new file mode 100644
index 0000000000..9aae74dc8e
--- /dev/null
+++ b/utils/fppkg/lnet/ltimer.pp
@@ -0,0 +1,61 @@
+unit ltimer;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils;
+
+type
+
+ { TLTimer }
+
+ TLTimer = class(TObject)
+ protected
+ FOnTimer: TNotifyEvent;
+ FInterval: TDateTime;
+ FStarted: TDateTime;
+ FOneShot: Boolean;
+ FEnabled: Boolean;
+
+ function GetInterval: Integer;
+ procedure SetInterval(const aValue: Integer);
+ public
+ procedure CallAction;
+ property Enabled: Boolean read FEnabled write FEnabled;
+ property Interval: Integer read GetInterval write SetInterval;
+ property OneShot: Boolean read FOneShot write FOneShot;
+ property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
+ end;
+
+implementation
+
+{ TLTimer }
+
+function TLTimer.GetInterval: Integer;
+begin
+ Result := Round(FInterval * MSecsPerDay);
+end;
+
+procedure TLTimer.SetInterval(const aValue: Integer);
+begin
+ FInterval := AValue / MSecsPerDay;
+ FStarted := Now;
+ FEnabled := true;
+end;
+
+procedure TLTimer.CallAction;
+begin
+ if FEnabled and Assigned(FOnTimer) and (Now - FStarted >= FInterval) then
+ begin
+ FOnTimer(Self);
+ if not FOneShot then
+ FStarted := Now
+ else
+ FEnabled := false;
+ end;
+end;
+
+end.
+
diff --git a/utils/fppkg/lnet/openssl.pp b/utils/fppkg/lnet/openssl.pp
deleted file mode 100644
index 465900e187..0000000000
--- a/utils/fppkg/lnet/openssl.pp
+++ /dev/null
@@ -1,1452 +0,0 @@
-unit OpenSSL;
-
-{==============================================================================|
-| Project : Ararat Synapse | 003.004.001 |
-|==============================================================================|
-| Content: SSL support by OpenSSL |
-|==============================================================================|
-| Copyright (c)1999-2005, Lukas Gebauer |
-| All rights reserved. |
-| |
-| Redistribution and use in source and binary forms, with or without |
-| modification, are permitted provided that the following conditions are met: |
-| |
-| Redistributions of source code must retain the above copyright notice, this |
-| list of conditions and the following disclaimer. |
-| |
-| Redistributions in binary form must reproduce the above copyright notice, |
-| this list of conditions and the following disclaimer in the documentation |
-| and/or other materials provided with the distribution. |
-| |
-| Neither the name of Lukas Gebauer nor the names of its contributors may |
-| be used to endorse or promote products derived from this software without |
-| specific prior written permission. |
-| |
-| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
-| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
-| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
-| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
-| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
-| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
-| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
-| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
-| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
-| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
-| DAMAGE. |
-|==============================================================================|
-| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
-| Portions created by Lukas Gebauer are Copyright (c)2002-2005. |
-| All Rights Reserved. |
-|==============================================================================|
-| Contributor(s): |
-|==============================================================================|
-| FreePascal basic cleanup (original worked too): Ales Katona |
-|==============================================================================|
-| History: see HISTORY.HTM from distribution package |
-| (Found at URL: http://www.ararat.cz/synapse/) |
-|==============================================================================}
-
-{
-Special thanks to Gregor Ibic
- (Intelicom d.o.o., http://www.intelicom.si)
- for good inspiration about begin with SSL programming.
-}
-
-{$MODE DELPHI}{$H+}
-
-{:@abstract(OpenSSL support)
-
-This unit is Pascal interface to OpenSSL library (used by @link(ssl_openssl) unit).
-OpenSSL is loaded dynamicly on-demand. If this library is not found in system,
-requested OpenSSL function just return errorcode.
-}
-
-interface
-
-uses
- DynLibs;
-
-var
- {$IFDEF WINDOWS}
- DLLSSLName: string = 'ssleay32.dll';
- DLLSSLName2: string = 'libssl32.dll';
- DLLUtilName: string = 'libeay32.dll';
- {$ELSE}
- DLLSSLName: string = 'libssl.so';
- DLLUtilName: string = 'libcrypto.so';
- {$ENDIF}
-
-type
- SslPtr = Pointer;
- PSslPtr = ^SslPtr;
- PSSL_CTX = SslPtr;
- PSSL = SslPtr;
- PSSL_METHOD = SslPtr;
- PX509 = SslPtr;
- PX509_NAME = SslPtr;
- PEVP_MD = SslPtr;
- PInteger = ^Integer;
- PBIO_METHOD = SslPtr;
- PBIO = SslPtr;
- EVP_PKEY = SslPtr;
- PRSA = SslPtr;
- PASN1_UTCTIME = SslPtr;
- PASN1_INTEGER = SslPtr;
- PPasswdCb = SslPtr;
- PFunction = procedure;
-
- DES_cblock = array[0..7] of Byte;
- PDES_cblock = ^DES_cblock;
- des_ks_struct = packed record
- ks: DES_cblock;
- weak_key: Integer;
- end;
- des_key_schedule = array[1..16] of des_ks_struct;
-
-const
- EVP_MAX_MD_SIZE = 16 + 20;
-
- SSL_ERROR_NONE = 0;
- SSL_ERROR_SSL = 1;
- SSL_ERROR_WANT_READ = 2;
- SSL_ERROR_WANT_WRITE = 3;
- SSL_ERROR_WANT_X509_LOOKUP = 4;
- SSL_ERROR_SYSCALL = 5; //look at error stack/return value/errno
- SSL_ERROR_ZERO_RETURN = 6;
- SSL_ERROR_WANT_CONNECT = 7;
- SSL_ERROR_WANT_ACCEPT = 8;
-
- SSL_OP_NO_SSLv2 = $01000000;
- SSL_OP_NO_SSLv3 = $02000000;
- SSL_OP_NO_TLSv1 = $04000000;
- SSL_OP_ALL = $000FFFFF;
- SSL_VERIFY_NONE = $00;
- SSL_VERIFY_PEER = $01;
-
- OPENSSL_DES_DECRYPT = 0;
- OPENSSL_DES_ENCRYPT = 1;
-
- X509_V_OK = 0;
- X509_V_ILLEGAL = 1;
- X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2;
- X509_V_ERR_UNABLE_TO_GET_CRL = 3;
- X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4;
- X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5;
- X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6;
- X509_V_ERR_CERT_SIGNATURE_FAILURE = 7;
- X509_V_ERR_CRL_SIGNATURE_FAILURE = 8;
- X509_V_ERR_CERT_NOT_YET_VALID = 9;
- X509_V_ERR_CERT_HAS_EXPIRED = 10;
- X509_V_ERR_CRL_NOT_YET_VALID = 11;
- X509_V_ERR_CRL_HAS_EXPIRED = 12;
- X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 13;
- X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD = 14;
- X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD = 15;
- X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 16;
- X509_V_ERR_OUT_OF_MEM = 17;
- X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT = 18;
- X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN = 19;
- X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20;
- X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21;
- X509_V_ERR_CERT_CHAIN_TOO_LONG = 22;
- X509_V_ERR_CERT_REVOKED = 23;
- X509_V_ERR_INVALID_CA = 24;
- X509_V_ERR_PATH_LENGTH_EXCEEDED = 25;
- X509_V_ERR_INVALID_PURPOSE = 26;
- X509_V_ERR_CERT_UNTRUSTED = 27;
- X509_V_ERR_CERT_REJECTED = 28;
- //These are 'informational' when looking for issuer cert
- X509_V_ERR_SUBJECT_ISSUER_MISMATCH = 29;
- X509_V_ERR_AKID_SKID_MISMATCH = 30;
- X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH = 31;
- X509_V_ERR_KEYUSAGE_NO_CERTSIGN = 32;
- X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER = 33;
- X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION = 34;
- //The application is not happy
- X509_V_ERR_APPLICATION_VERIFICATION = 50;
-
- SSL_FILETYPE_ASN1 = 2;
- SSL_FILETYPE_PEM = 1;
- EVP_PKEY_RSA = 6;
-
-var
- SSLLibHandle: TLibHandle = 0;
- SSLUtilHandle: TLibHandle = 0;
- SSLLibFile: string = '';
- SSLUtilFile: string = '';
-
-// libssl.dll
- function SslGetError(s: PSSL; ret_code: Integer):Integer;
- function SslLibraryInit:Integer;
- procedure SslLoadErrorStrings;
-// function SslCtxSetCipherList(arg0: PSSL_CTX; str: PChar):Integer;
- function SslCtxSetCipherList(arg0: PSSL_CTX; var str: String):Integer;
- function SslCtxNew(meth: PSSL_METHOD):PSSL_CTX;
- procedure SslCtxFree(arg0: PSSL_CTX);
- function SslSetFd(s: PSSL; fd: Integer):Integer;
- function SslMethodV2:PSSL_METHOD;
- function SslMethodV3:PSSL_METHOD;
- function SslMethodTLSV1:PSSL_METHOD;
- function SslMethodV23:PSSL_METHOD;
- function SslCtxUsePrivateKey(ctx: PSSL_CTX; pkey: SslPtr):Integer;
- function SslCtxUsePrivateKeyASN1(pk: integer; ctx: PSSL_CTX; d: String; len: integer):Integer;
-// function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: PChar; _type: Integer):Integer;
- function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: String; _type: Integer):Integer;
- function SslCtxUseCertificate(ctx: PSSL_CTX; x: SslPtr):Integer;
- function SslCtxUseCertificateASN1(ctx: PSSL_CTX; len: integer; d: String):Integer;
- function SslCtxUseCertificateFile(ctx: PSSL_CTX; const _file: String; _type: Integer):Integer;
-// function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: PChar):Integer;
- function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: String):Integer;
- function SslCtxCheckPrivateKeyFile(ctx: PSSL_CTX):Integer;
- procedure SslCtxSetDefaultPasswdCb(ctx: PSSL_CTX; cb: PPasswdCb);
- procedure SslCtxSetDefaultPasswdCbUserdata(ctx: PSSL_CTX; u: SslPtr);
-// function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: PChar; const CApath: PChar):Integer;
- function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: String; const CApath: String):Integer;
- function SslNew(ctx: PSSL_CTX):PSSL;
- procedure SslFree(ssl: PSSL);
- function SslAccept(ssl: PSSL):Integer;
- function SslConnect(ssl: PSSL):Integer;
- function SslShutdown(ssl: PSSL):Integer;
- function SslRead(ssl: PSSL; buf: SslPtr; num: Integer):Integer;
- function SslPeek(ssl: PSSL; buf: SslPtr; num: Integer):Integer;
- function SslWrite(ssl: PSSL; buf: SslPtr; num: Integer):Integer;
- function SslPending(ssl: PSSL):Integer;
- function SslGetVersion(ssl: PSSL):String;
- function SslGetPeerCertificate(ssl: PSSL):PX509;
- procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: PFunction);
- function SSLGetCurrentCipher(s: PSSL):SslPtr;
- function SSLCipherGetName(c: SslPtr): String;
- function SSLCipherGetBits(c: SslPtr; var alg_bits: Integer):Integer;
- function SSLGetVerifyResult(ssl: PSSL):Integer;
-
-// libeay.dll
- function X509New: PX509;
- procedure X509Free(x: PX509);
- function X509NameOneline(a: PX509_NAME; var buf: String; size: Integer):String;
- function X509GetSubjectName(a: PX509):PX509_NAME;
- function X509GetIssuerName(a: PX509):PX509_NAME;
- function X509NameHash(x: PX509_NAME):Cardinal;
-// function SslX509Digest(data: PX509; _type: PEVP_MD; md: PChar; len: PInteger):Integer;
- function X509Digest(data: PX509; _type: PEVP_MD; md: String; var len: Integer):Integer;
- function X509print(b: PBIO; a: PX509): integer;
- function X509SetVersion(x: PX509; version: integer): integer;
- function X509SetPubkey(x: PX509; pkey: EVP_PKEY): integer;
- function X509SetIssuerName(x: PX509; name: PX509_NAME): integer;
- function X509NameAddEntryByTxt(name: PX509_NAME; field: string; _type: integer;
- bytes: string; len, loc, _set: integer): integer;
- function X509Sign(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer;
- function X509GmtimeAdj(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME;
- function X509SetNotBefore(x: PX509; tm: PASN1_UTCTIME): integer;
- function X509SetNotAfter(x: PX509; tm: PASN1_UTCTIME): integer;
- function X509GetSerialNumber(x: PX509): PASN1_INTEGER;
- function EvpPkeyNew: EVP_PKEY;
- procedure EvpPkeyFree(pk: EVP_PKEY);
- function EvpPkeyAssign(pkey: EVP_PKEY; _type: integer; key: Prsa): integer;
- function EvpGetDigestByName(Name: String): PEVP_MD;
- procedure EVPcleanup;
-// function ErrErrorString(e: integer; buf: PChar): PChar;
- function SSLeayversion(t: integer): string;
- procedure ErrErrorString(e: integer; var buf: string; len: integer);
- function ErrGetError: integer;
- procedure ErrClearError;
- procedure ErrFreeStrings;
- procedure ErrRemoveState(pid: integer);
- procedure OPENSSLaddallalgorithms;
- procedure CRYPTOcleanupAllExData;
- procedure RandScreen;
- function BioNew(b: PBIO_METHOD): PBIO;
- procedure BioFreeAll(b: PBIO);
- function BioSMem: PBIO_METHOD;
- function BioCtrlPending(b: PBIO): integer;
- function BioRead(b: PBIO; var Buf: String; Len: integer): integer;
- function BioWrite(b: PBIO; Buf: String; Len: integer): integer;
- function d2iPKCS12bio(b:PBIO; Pkcs12: SslPtr): SslPtr;
- function PKCS12parse(p12: SslPtr; pass: string; var pkey, cert, ca: SslPtr): integer;
- procedure PKCS12free(p12: SslPtr);
- function RsaGenerateKey(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA;
- function Asn1UtctimeNew: PASN1_UTCTIME;
- procedure Asn1UtctimeFree(a: PASN1_UTCTIME);
- function Asn1IntegerSet(a: PASN1_INTEGER; v: integer): integer;
- function i2dX509bio(b: PBIO; x: PX509): integer;
- function i2dPrivateKeyBio(b: PBIO; pkey: EVP_PKEY): integer;
-
- // 3DES functions
- procedure DESsetoddparity(Key: des_cblock);
- function DESsetkeychecked(key: des_cblock; schedule: des_key_schedule): Integer;
- procedure DESecbencrypt(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer);
-
-function IsSSLloaded: Boolean;
-function InitSSLInterface: Boolean;
-function DestroySSLInterface: Boolean;
-
-implementation
-
-type
-// libssl.dll
- TSslGetError = function(s: PSSL; ret_code: Integer):Integer; cdecl;
- TSslLibraryInit = function:Integer; cdecl;
- TSslLoadErrorStrings = procedure; cdecl;
- TSslCtxSetCipherList = function(arg0: PSSL_CTX; str: PChar):Integer; cdecl;
- TSslCtxNew = function(meth: PSSL_METHOD):PSSL_CTX; cdecl;
- TSslCtxFree = procedure(arg0: PSSL_CTX); cdecl;
- TSslSetFd = function(s: PSSL; fd: Integer):Integer; cdecl;
- TSslMethodV2 = function:PSSL_METHOD; cdecl;
- TSslMethodV3 = function:PSSL_METHOD; cdecl;
- TSslMethodTLSV1 = function:PSSL_METHOD; cdecl;
- TSslMethodV23 = function:PSSL_METHOD; cdecl;
- TSslCtxUsePrivateKey = function(ctx: PSSL_CTX; pkey: sslptr):Integer; cdecl;
- TSslCtxUsePrivateKeyASN1 = function(pk: integer; ctx: PSSL_CTX; d: sslptr; len: integer):Integer; cdecl;
- TSslCtxUsePrivateKeyFile = function(ctx: PSSL_CTX; const _file: PChar; _type: Integer):Integer; cdecl;
- TSslCtxUseCertificate = function(ctx: PSSL_CTX; x: SslPtr):Integer; cdecl;
- TSslCtxUseCertificateASN1 = function(ctx: PSSL_CTX; len: Integer; d: SslPtr):Integer; cdecl;
- TSslCtxUseCertificateFile = function(ctx: PSSL_CTX; const _file: PChar; _type: Integer):Integer; cdecl;
- TSslCtxUseCertificateChainFile = function(ctx: PSSL_CTX; const _file: PChar):Integer; cdecl;
- TSslCtxCheckPrivateKeyFile = function(ctx: PSSL_CTX):Integer; cdecl;
- TSslCtxSetDefaultPasswdCb = procedure(ctx: PSSL_CTX; cb: SslPtr); cdecl;
- TSslCtxSetDefaultPasswdCbUserdata = procedure(ctx: PSSL_CTX; u: SslPtr); cdecl;
- TSslCtxLoadVerifyLocations = function(ctx: PSSL_CTX; const CAfile: PChar; const CApath: PChar):Integer; cdecl;
- TSslNew = function(ctx: PSSL_CTX):PSSL; cdecl;
- TSslFree = procedure(ssl: PSSL); cdecl;
- TSslAccept = function(ssl: PSSL):Integer; cdecl;
- TSslConnect = function(ssl: PSSL):Integer; cdecl;
- TSslShutdown = function(ssl: PSSL):Integer; cdecl;
- TSslRead = function(ssl: PSSL; buf: PChar; num: Integer):Integer; cdecl;
- TSslPeek = function(ssl: PSSL; buf: PChar; num: Integer):Integer; cdecl;
- TSslWrite = function(ssl: PSSL; const buf: PChar; num: Integer):Integer; cdecl;
- TSslPending = function(ssl: PSSL):Integer; cdecl;
- TSslGetVersion = function(ssl: PSSL):PChar; cdecl;
- TSslGetPeerCertificate = function(ssl: PSSL):PX509; cdecl;
- TSslCtxSetVerify = procedure(ctx: PSSL_CTX; mode: Integer; arg2: SslPtr); cdecl;
- TSSLGetCurrentCipher = function(s: PSSL):SslPtr; cdecl;
- TSSLCipherGetName = function(c: Sslptr):PChar; cdecl;
- TSSLCipherGetBits = function(c: SslPtr; alg_bits: PInteger):Integer; cdecl;
- TSSLGetVerifyResult = function(ssl: PSSL):Integer; cdecl;
-
-// libeay.dll
- TX509New = function: PX509; cdecl;
- TX509Free = procedure(x: PX509); cdecl;
- TX509NameOneline = function(a: PX509_NAME; buf: PChar; size: Integer):PChar; cdecl;
- TX509GetSubjectName = function(a: PX509):PX509_NAME; cdecl;
- TX509GetIssuerName = function(a: PX509):PX509_NAME; cdecl;
- TX509NameHash = function(x: PX509_NAME):Cardinal; cdecl;
- TX509Digest = function(data: PX509; _type: PEVP_MD; md: PChar; len: PInteger):Integer; cdecl;
- TX509print = function(b: PBIO; a: PX509): integer; cdecl;
- TX509SetVersion = function(x: PX509; version: integer): integer; cdecl;
- TX509SetPubkey = function(x: PX509; pkey: EVP_PKEY): integer; cdecl;
- TX509SetIssuerName = function(x: PX509; name: PX509_NAME): integer; cdecl;
- TX509NameAddEntryByTxt = function(name: PX509_NAME; field: PChar; _type: integer;
- bytes: PChar; len, loc, _set: integer): integer; cdecl;
- TX509Sign = function(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer; cdecl;
- TX509GmtimeAdj = function(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME; cdecl;
- TX509SetNotBefore = function(x: PX509; tm: PASN1_UTCTIME): integer; cdecl;
- TX509SetNotAfter = function(x: PX509; tm: PASN1_UTCTIME): integer; cdecl;
- TX509GetSerialNumber = function(x: PX509): PASN1_INTEGER; cdecl;
- TEvpPkeyNew = function: EVP_PKEY; cdecl;
- TEvpPkeyFree = procedure(pk: EVP_PKEY); cdecl;
- TEvpPkeyAssign = function(pkey: EVP_PKEY; _type: integer; key: Prsa): integer; cdecl;
- TEvpGetDigestByName = function(Name: PChar): PEVP_MD; cdecl;
- TEVPcleanup = procedure; cdecl;
- TSSLeayversion = function(t: integer): PChar; cdecl;
- TErrErrorString = procedure(e: integer; buf: PChar; len: integer); cdecl;
- TErrGetError = function: integer; cdecl;
- TErrClearError = procedure; cdecl;
- TErrFreeStrings = procedure; cdecl;
- TErrRemoveState = procedure(pid: integer); cdecl;
- TOPENSSLaddallalgorithms = procedure; cdecl;
- TCRYPTOcleanupAllExData = procedure; cdecl;
- TRandScreen = procedure; cdecl;
- TBioNew = function(b: PBIO_METHOD): PBIO; cdecl;
- TBioFreeAll = procedure(b: PBIO); cdecl;
- TBioSMem = function: PBIO_METHOD; cdecl;
- TBioCtrlPending = function(b: PBIO): integer; cdecl;
- TBioRead = function(b: PBIO; Buf: PChar; Len: integer): integer; cdecl;
- TBioWrite = function(b: PBIO; Buf: PChar; Len: integer): integer; cdecl;
- Td2iPKCS12bio = function(b:PBIO; Pkcs12: SslPtr): SslPtr; cdecl;
- TPKCS12parse = function(p12: SslPtr; pass: PChar; var pkey, cert, ca: SslPtr): integer; cdecl;
- TPKCS12free = procedure(p12: SslPtr); cdecl;
- TRsaGenerateKey = function(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA; cdecl;
- TAsn1UtctimeNew = function: PASN1_UTCTIME; cdecl;
- TAsn1UtctimeFree = procedure(a: PASN1_UTCTIME); cdecl;
- TAsn1IntegerSet = function(a: PASN1_INTEGER; v: integer): integer; cdecl;
- Ti2dX509bio = function(b: PBIO; x: PX509): integer; cdecl;
- Ti2dPrivateKeyBio= function(b: PBIO; pkey: EVP_PKEY): integer; cdecl;
-
- // 3DES functions
- TDESsetoddparity = procedure(Key: des_cblock); cdecl;
- TDESsetkeychecked = function(key: des_cblock; schedule: des_key_schedule): Integer; cdecl;
- TDESecbencrypt = procedure(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer); cdecl;
- //thread lock functions
- TCRYPTOnumlocks = function: integer; cdecl;
- TCRYPTOSetLockingCallback = procedure(cb: Sslptr); cdecl;
-
-var
-// libssl.dll
- _SslGetError: TSslGetError = nil;
- _SslLibraryInit: TSslLibraryInit = nil;
- _SslLoadErrorStrings: TSslLoadErrorStrings = nil;
- _SslCtxSetCipherList: TSslCtxSetCipherList = nil;
- _SslCtxNew: TSslCtxNew = nil;
- _SslCtxFree: TSslCtxFree = nil;
- _SslSetFd: TSslSetFd = nil;
- _SslMethodV2: TSslMethodV2 = nil;
- _SslMethodV3: TSslMethodV3 = nil;
- _SslMethodTLSV1: TSslMethodTLSV1 = nil;
- _SslMethodV23: TSslMethodV23 = nil;
- _SslCtxUsePrivateKey: TSslCtxUsePrivateKey = nil;
- _SslCtxUsePrivateKeyASN1: TSslCtxUsePrivateKeyASN1 = nil;
- _SslCtxUsePrivateKeyFile: TSslCtxUsePrivateKeyFile = nil;
- _SslCtxUseCertificate: TSslCtxUseCertificate = nil;
- _SslCtxUseCertificateASN1: TSslCtxUseCertificateASN1 = nil;
- _SslCtxUseCertificateFile: TSslCtxUseCertificateFile = nil;
- _SslCtxUseCertificateChainFile: TSslCtxUseCertificateChainFile = nil;
- _SslCtxCheckPrivateKeyFile: TSslCtxCheckPrivateKeyFile = nil;
- _SslCtxSetDefaultPasswdCb: TSslCtxSetDefaultPasswdCb = nil;
- _SslCtxSetDefaultPasswdCbUserdata: TSslCtxSetDefaultPasswdCbUserdata = nil;
- _SslCtxLoadVerifyLocations: TSslCtxLoadVerifyLocations = nil;
- _SslNew: TSslNew = nil;
- _SslFree: TSslFree = nil;
- _SslAccept: TSslAccept = nil;
- _SslConnect: TSslConnect = nil;
- _SslShutdown: TSslShutdown = nil;
- _SslRead: TSslRead = nil;
- _SslPeek: TSslPeek = nil;
- _SslWrite: TSslWrite = nil;
- _SslPending: TSslPending = nil;
- _SslGetVersion: TSslGetVersion = nil;
- _SslGetPeerCertificate: TSslGetPeerCertificate = nil;
- _SslCtxSetVerify: TSslCtxSetVerify = nil;
- _SSLGetCurrentCipher: TSSLGetCurrentCipher = nil;
- _SSLCipherGetName: TSSLCipherGetName = nil;
- _SSLCipherGetBits: TSSLCipherGetBits = nil;
- _SSLGetVerifyResult: TSSLGetVerifyResult = nil;
-
-// libeay.dll
- _X509New: TX509New = nil;
- _X509Free: TX509Free = nil;
- _X509NameOneline: TX509NameOneline = nil;
- _X509GetSubjectName: TX509GetSubjectName = nil;
- _X509GetIssuerName: TX509GetIssuerName = nil;
- _X509NameHash: TX509NameHash = nil;
- _X509Digest: TX509Digest = nil;
- _X509print: TX509print = nil;
- _X509SetVersion: TX509SetVersion = nil;
- _X509SetPubkey: TX509SetPubkey = nil;
- _X509SetIssuerName: TX509SetIssuerName = nil;
- _X509NameAddEntryByTxt: TX509NameAddEntryByTxt = nil;
- _X509Sign: TX509Sign = nil;
- _X509GmtimeAdj: TX509GmtimeAdj = nil;
- _X509SetNotBefore: TX509SetNotBefore = nil;
- _X509SetNotAfter: TX509SetNotAfter = nil;
- _X509GetSerialNumber: TX509GetSerialNumber = nil;
- _EvpPkeyNew: TEvpPkeyNew = nil;
- _EvpPkeyFree: TEvpPkeyFree = nil;
- _EvpPkeyAssign: TEvpPkeyAssign = nil;
- _EvpGetDigestByName: TEvpGetDigestByName = nil;
- _EVPcleanup: TEVPcleanup = nil;
- _SSLeayversion: TSSLeayversion = nil;
- _ErrErrorString: TErrErrorString = nil;
- _ErrGetError: TErrGetError = nil;
- _ErrClearError: TErrClearError = nil;
- _ErrFreeStrings: TErrFreeStrings = nil;
- _ErrRemoveState: TErrRemoveState = nil;
- _OPENSSLaddallalgorithms: TOPENSSLaddallalgorithms = nil;
- _CRYPTOcleanupAllExData: TCRYPTOcleanupAllExData = nil;
- _RandScreen: TRandScreen = nil;
- _BioNew: TBioNew = nil;
- _BioFreeAll: TBioFreeAll = nil;
- _BioSMem: TBioSMem = nil;
- _BioCtrlPending: TBioCtrlPending = nil;
- _BioRead: TBioRead = nil;
- _BioWrite: TBioWrite = nil;
- _d2iPKCS12bio: Td2iPKCS12bio = nil;
- _PKCS12parse: TPKCS12parse = nil;
- _PKCS12free: TPKCS12free = nil;
- _RsaGenerateKey: TRsaGenerateKey = nil;
- _Asn1UtctimeNew: TAsn1UtctimeNew = nil;
- _Asn1UtctimeFree: TAsn1UtctimeFree = nil;
- _Asn1IntegerSet: TAsn1IntegerSet = nil;
- _i2dX509bio: Ti2dX509bio = nil;
- _i2dPrivateKeyBio: Ti2dPrivateKeyBio = nil;
-
- // 3DES functions
- _DESsetoddparity: TDESsetoddparity = nil;
- _DESsetkeychecked: TDESsetkeychecked = nil;
- _DESecbencrypt: TDESecbencrypt = nil;
- //thread lock functions
- _CRYPTOnumlocks: TCRYPTOnumlocks = nil;
- _CRYPTOSetLockingCallback: TCRYPTOSetLockingCallback = nil;
-
-var
- SSLloaded: boolean = false;
-
-// libssl.dll
-function SslGetError(s: PSSL; ret_code: Integer):Integer;
-begin
- if InitSSLInterface and Assigned(_SslGetError) then
- Result := _SslGetError(s, ret_code)
- else
- Result := SSL_ERROR_SSL;
-end;
-
-function SslLibraryInit:Integer;
-begin
- if InitSSLInterface and Assigned(_SslLibraryInit) then
- Result := _SslLibraryInit
- else
- Result := 1;
-end;
-
-procedure SslLoadErrorStrings;
-begin
- if InitSSLInterface and Assigned(_SslLoadErrorStrings) then
- _SslLoadErrorStrings;
-end;
-
-//function SslCtxSetCipherList(arg0: PSSL_CTX; str: PChar):Integer;
-function SslCtxSetCipherList(arg0: PSSL_CTX; var str: String):Integer;
-begin
- if InitSSLInterface and Assigned(_SslCtxSetCipherList) then
- Result := _SslCtxSetCipherList(arg0, PChar(str))
- else
- Result := 0;
-end;
-
-function SslCtxNew(meth: PSSL_METHOD):PSSL_CTX;
-begin
- if InitSSLInterface and Assigned(_SslCtxNew) then
- Result := _SslCtxNew(meth)
- else
- Result := nil;
-end;
-
-procedure SslCtxFree(arg0: PSSL_CTX);
-begin
- if InitSSLInterface and Assigned(_SslCtxFree) then
- _SslCtxFree(arg0);
-end;
-
-function SslSetFd(s: PSSL; fd: Integer):Integer;
-begin
- if InitSSLInterface and Assigned(_SslSetFd) then
- Result := _SslSetFd(s, fd)
- else
- Result := 0;
-end;
-
-function SslMethodV2:PSSL_METHOD;
-begin
- if InitSSLInterface and Assigned(_SslMethodV2) then
- Result := _SslMethodV2
- else
- Result := nil;
-end;
-
-function SslMethodV3:PSSL_METHOD;
-begin
- if InitSSLInterface and Assigned(_SslMethodV3) then
- Result := _SslMethodV3
- else
- Result := nil;
-end;
-
-function SslMethodTLSV1:PSSL_METHOD;
-begin
- if InitSSLInterface and Assigned(_SslMethodTLSV1) then
- Result := _SslMethodTLSV1
- else
- Result := nil;
-end;
-
-function SslMethodV23:PSSL_METHOD;
-begin
- if InitSSLInterface and Assigned(_SslMethodV23) then
- Result := _SslMethodV23
- else
- Result := nil;
-end;
-
-function SslCtxUsePrivateKey(ctx: PSSL_CTX; pkey: SslPtr):Integer;
-begin
- if InitSSLInterface and Assigned(_SslCtxUsePrivateKey) then
- Result := _SslCtxUsePrivateKey(ctx, pkey)
- else
- Result := 0;
-end;
-
-function SslCtxUsePrivateKeyASN1(pk: integer; ctx: PSSL_CTX; d: String; len: integer):Integer;
-begin
- if InitSSLInterface and Assigned(_SslCtxUsePrivateKeyASN1) then
- Result := _SslCtxUsePrivateKeyASN1(pk, ctx, Sslptr(d), len)
- else
- Result := 0;
-end;
-
-//function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: PChar; _type: Integer):Integer;
-function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: String; _type: Integer):Integer;
-begin
- if InitSSLInterface and Assigned(_SslCtxUsePrivateKeyFile) then
- Result := _SslCtxUsePrivateKeyFile(ctx, PChar(_file), _type)
- else
- Result := 0;
-end;
-
-function SslCtxUseCertificate(ctx: PSSL_CTX; x: SslPtr):Integer;
-begin
- if InitSSLInterface and Assigned(_SslCtxUseCertificate) then
- Result := _SslCtxUseCertificate(ctx, x)
- else
- Result := 0;
-end;
-
-function SslCtxUseCertificateASN1(ctx: PSSL_CTX; len: integer; d: String):Integer;
-begin
- if InitSSLInterface and Assigned(_SslCtxUseCertificateASN1) then
- Result := _SslCtxUseCertificateASN1(ctx, len, SslPtr(d))
- else
- Result := 0;
-end;
-
-function SslCtxUseCertificateFile(ctx: PSSL_CTX; const _file: String; _type: Integer):Integer;
-begin
- if InitSSLInterface and Assigned(_SslCtxUseCertificateFile) then
- Result := _SslCtxUseCertificateFile(ctx, PChar(_file), _type)
- else
- Result := 0;
-end;
-
-//function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: PChar):Integer;
-function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: String):Integer;
-begin
- if InitSSLInterface and Assigned(_SslCtxUseCertificateChainFile) then
- Result := _SslCtxUseCertificateChainFile(ctx, PChar(_file))
- else
- Result := 0;
-end;
-
-function SslCtxCheckPrivateKeyFile(ctx: PSSL_CTX):Integer;
-begin
- if InitSSLInterface and Assigned(_SslCtxCheckPrivateKeyFile) then
- Result := _SslCtxCheckPrivateKeyFile(ctx)
- else
- Result := 0;
-end;
-
-procedure SslCtxSetDefaultPasswdCb(ctx: PSSL_CTX; cb: PPasswdCb);
-begin
- if InitSSLInterface and Assigned(_SslCtxSetDefaultPasswdCb) then
- _SslCtxSetDefaultPasswdCb(ctx, cb);
-end;
-
-procedure SslCtxSetDefaultPasswdCbUserdata(ctx: PSSL_CTX; u: SslPtr);
-begin
- if InitSSLInterface and Assigned(_SslCtxSetDefaultPasswdCbUserdata) then
- _SslCtxSetDefaultPasswdCbUserdata(ctx, u);
-end;
-
-//function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: PChar; const CApath: PChar):Integer;
-function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: String; const CApath: String):Integer;
-begin
- if InitSSLInterface and Assigned(_SslCtxLoadVerifyLocations) then
- Result := _SslCtxLoadVerifyLocations(ctx, SslPtr(CAfile), SslPtr(CApath))
- else
- Result := 0;
-end;
-
-function SslNew(ctx: PSSL_CTX):PSSL;
-begin
- if InitSSLInterface and Assigned(_SslNew) then
- Result := _SslNew(ctx)
- else
- Result := nil;
-end;
-
-procedure SslFree(ssl: PSSL);
-begin
- if InitSSLInterface and Assigned(_SslFree) then
- _SslFree(ssl);
-end;
-
-function SslAccept(ssl: PSSL):Integer;
-begin
- if InitSSLInterface and Assigned(_SslAccept) then
- Result := _SslAccept(ssl)
- else
- Result := -1;
-end;
-
-function SslConnect(ssl: PSSL):Integer;
-begin
- if InitSSLInterface and Assigned(_SslConnect) then
- Result := _SslConnect(ssl)
- else
- Result := -1;
-end;
-
-function SslShutdown(ssl: PSSL):Integer;
-begin
- if InitSSLInterface and Assigned(_SslShutdown) then
- Result := _SslShutdown(ssl)
- else
- Result := -1;
-end;
-
-//function SslRead(ssl: PSSL; buf: PChar; num: Integer):Integer;
-function SslRead(ssl: PSSL; buf: SslPtr; num: Integer):Integer;
-begin
- if InitSSLInterface and Assigned(_SslRead) then
- Result := _SslRead(ssl, PChar(buf), num)
- else
- Result := -1;
-end;
-
-//function SslPeek(ssl: PSSL; buf: PChar; num: Integer):Integer;
-function SslPeek(ssl: PSSL; buf: SslPtr; num: Integer):Integer;
-begin
- if InitSSLInterface and Assigned(_SslPeek) then
- Result := _SslPeek(ssl, PChar(buf), num)
- else
- Result := -1;
-end;
-
-//function SslWrite(ssl: PSSL; const buf: PChar; num: Integer):Integer;
-function SslWrite(ssl: PSSL; buf: SslPtr; num: Integer):Integer;
-begin
- if InitSSLInterface and Assigned(_SslWrite) then
- Result := _SslWrite(ssl, PChar(buf), num)
- else
- Result := -1;
-end;
-
-function SslPending(ssl: PSSL):Integer;
-begin
- if InitSSLInterface and Assigned(_SslPending) then
- Result := _SslPending(ssl)
- else
- Result := 0;
-end;
-
-//function SslGetVersion(ssl: PSSL):PChar;
-function SslGetVersion(ssl: PSSL):String;
-begin
- if InitSSLInterface and Assigned(_SslGetVersion) then
- Result := _SslGetVersion(ssl)
- else
- Result := '';
-end;
-
-function SslGetPeerCertificate(ssl: PSSL):PX509;
-begin
- if InitSSLInterface and Assigned(_SslGetPeerCertificate) then
- Result := _SslGetPeerCertificate(ssl)
- else
- Result := nil;
-end;
-
-//procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: SslPtr);
-procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: PFunction);
-begin
- if InitSSLInterface and Assigned(_SslCtxSetVerify) then
- _SslCtxSetVerify(ctx, mode, @arg2);
-end;
-
-function SSLGetCurrentCipher(s: PSSL):SslPtr;
-begin
- if InitSSLInterface and Assigned(_SSLGetCurrentCipher) then
-{$IFDEF CIL}
-{$ELSE}
- Result := _SSLGetCurrentCipher(s)
-{$ENDIF}
- else
- Result := nil;
-end;
-
-//function SSLCipherGetName(c: SslPtr):PChar;
-function SSLCipherGetName(c: SslPtr):String;
-begin
- if InitSSLInterface and Assigned(_SSLCipherGetName) then
- Result := _SSLCipherGetName(c)
- else
- Result := '';
-end;
-
-//function SSLCipherGetBits(c: SslPtr; alg_bits: PInteger):Integer;
-function SSLCipherGetBits(c: SslPtr; var alg_bits: Integer):Integer;
-begin
- if InitSSLInterface and Assigned(_SSLCipherGetBits) then
- Result := _SSLCipherGetBits(c, @alg_bits)
- else
- Result := 0;
-end;
-
-function SSLGetVerifyResult(ssl: PSSL):Integer;
-begin
- if InitSSLInterface and Assigned(_SSLGetVerifyResult) then
- Result := _SSLGetVerifyResult(ssl)
- else
- Result := X509_V_ERR_APPLICATION_VERIFICATION;
-end;
-
-// libeay.dll
-function X509New: PX509;
-begin
- if InitSSLInterface and Assigned(_X509New) then
- Result := _X509New
- else
- Result := nil;
-end;
-
-procedure X509Free(x: PX509);
-begin
- if InitSSLInterface and Assigned(_X509Free) then
- _X509Free(x);
-end;
-
-//function SslX509NameOneline(a: PX509_NAME; buf: PChar; size: Integer):PChar;
-function X509NameOneline(a: PX509_NAME; var buf: String; size: Integer):String;
-begin
- if InitSSLInterface and Assigned(_X509NameOneline) then
- Result := _X509NameOneline(a, PChar(buf),size)
- else
- Result := '';
-end;
-
-function X509GetSubjectName(a: PX509):PX509_NAME;
-begin
- if InitSSLInterface and Assigned(_X509GetSubjectName) then
- Result := _X509GetSubjectName(a)
- else
- Result := nil;
-end;
-
-function X509GetIssuerName(a: PX509):PX509_NAME;
-begin
- if InitSSLInterface and Assigned(_X509GetIssuerName) then
- Result := _X509GetIssuerName(a)
- else
- Result := nil;
-end;
-
-function X509NameHash(x: PX509_NAME):Cardinal;
-begin
- if InitSSLInterface and Assigned(_X509NameHash) then
- Result := _X509NameHash(x)
- else
- Result := 0;
-end;
-
-//function SslX509Digest(data: PX509; _type: PEVP_MD; md: PChar; len: PInteger):Integer;
-function X509Digest(data: PX509; _type: PEVP_MD; md: String; var len: Integer):Integer;
-begin
- if InitSSLInterface and Assigned(_X509Digest) then
- Result := _X509Digest(data, _type, PChar(md), @len)
- else
- Result := 0;
-end;
-
-function EvpPkeyNew: EVP_PKEY;
-begin
- if InitSSLInterface and Assigned(_EvpPkeyNew) then
- Result := _EvpPkeyNew
- else
- Result := nil;
-end;
-
-procedure EvpPkeyFree(pk: EVP_PKEY);
-begin
- if InitSSLInterface and Assigned(_EvpPkeyFree) then
- _EvpPkeyFree(pk);
-end;
-
-function SSLeayversion(t: integer): string;
-begin
- if InitSSLInterface and Assigned(_SSLeayversion) then
- Result := PChar(_SSLeayversion(t))
- else
- Result := '';
-end;
-
-procedure ErrErrorString(e: integer; var buf: string; len: integer);
-begin
- if InitSSLInterface and Assigned(_ErrErrorString) then
- _ErrErrorString(e, Pointer(buf), len);
- buf := PChar(Buf);
-end;
-
-function ErrGetError: integer;
-begin
- if InitSSLInterface and Assigned(_ErrGetError) then
- Result := _ErrGetError
- else
- Result := SSL_ERROR_SSL;
-end;
-
-procedure ErrClearError;
-begin
- if InitSSLInterface and Assigned(_ErrClearError) then
- _ErrClearError;
-end;
-
-procedure ErrFreeStrings;
-begin
- if InitSSLInterface and Assigned(_ErrFreeStrings) then
- _ErrFreeStrings;
-end;
-
-procedure ErrRemoveState(pid: integer);
-begin
- if InitSSLInterface and Assigned(_ErrRemoveState) then
- _ErrRemoveState(pid);
-end;
-
-procedure OPENSSLaddallalgorithms;
-begin
- if InitSSLInterface and Assigned(_OPENSSLaddallalgorithms) then
- _OPENSSLaddallalgorithms;
-end;
-
-procedure EVPcleanup;
-begin
- if InitSSLInterface and Assigned(_EVPcleanup) then
- _EVPcleanup;
-end;
-
-procedure CRYPTOcleanupAllExData;
-begin
- if InitSSLInterface and Assigned(_CRYPTOcleanupAllExData) then
- _CRYPTOcleanupAllExData;
-end;
-
-procedure RandScreen;
-begin
- if InitSSLInterface and Assigned(_RandScreen) then
- _RandScreen;
-end;
-
-function BioNew(b: PBIO_METHOD): PBIO;
-begin
- if InitSSLInterface and Assigned(_BioNew) then
- Result := _BioNew(b)
- else
- Result := nil;
-end;
-
-procedure BioFreeAll(b: PBIO);
-begin
- if InitSSLInterface and Assigned(_BioFreeAll) then
- _BioFreeAll(b);
-end;
-
-function BioSMem: PBIO_METHOD;
-begin
- if InitSSLInterface and Assigned(_BioSMem) then
- Result := _BioSMem
- else
- Result := nil;
-end;
-
-function BioCtrlPending(b: PBIO): integer;
-begin
- if InitSSLInterface and Assigned(_BioCtrlPending) then
- Result := _BioCtrlPending(b)
- else
- Result := 0;
-end;
-
-//function BioRead(b: PBIO; Buf: PChar; Len: integer): integer;
-function BioRead(b: PBIO; var Buf: String; Len: integer): integer;
-begin
- if InitSSLInterface and Assigned(_BioRead) then
- Result := _BioRead(b, PChar(Buf), Len)
- else
- Result := -2;
-end;
-
-//function BioWrite(b: PBIO; Buf: PChar; Len: integer): integer;
-function BioWrite(b: PBIO; Buf: String; Len: integer): integer;
-begin
- if InitSSLInterface and Assigned(_BioWrite) then
- Result := _BioWrite(b, PChar(Buf), Len)
- else
- Result := -2;
-end;
-
-function X509print(b: PBIO; a: PX509): integer;
-begin
- if InitSSLInterface and Assigned(_X509print) then
- Result := _X509print(b, a)
- else
- Result := 0;
-end;
-
-function d2iPKCS12bio(b:PBIO; Pkcs12: SslPtr): SslPtr;
-begin
- if InitSSLInterface and Assigned(_d2iPKCS12bio) then
- Result := _d2iPKCS12bio(b, Pkcs12)
- else
- Result := nil;
-end;
-
-function PKCS12parse(p12: SslPtr; pass: string; var pkey, cert, ca: SslPtr): integer;
-begin
- if InitSSLInterface and Assigned(_PKCS12parse) then
- Result := _PKCS12parse(p12, SslPtr(pass), pkey, cert, ca)
- else
- Result := 0;
-end;
-
-procedure PKCS12free(p12: SslPtr);
-begin
- if InitSSLInterface and Assigned(_PKCS12free) then
- _PKCS12free(p12);
-end;
-
-function RsaGenerateKey(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA;
-begin
- if InitSSLInterface and Assigned(_RsaGenerateKey) then
- Result := _RsaGenerateKey(bits, e, callback, cb_arg)
- else
- Result := nil;
-end;
-
-function EvpPkeyAssign(pkey: EVP_PKEY; _type: integer; key: Prsa): integer;
-begin
- if InitSSLInterface and Assigned(_EvpPkeyAssign) then
- Result := _EvpPkeyAssign(pkey, _type, key)
- else
- Result := 0;
-end;
-
-function X509SetVersion(x: PX509; version: integer): integer;
-begin
- if InitSSLInterface and Assigned(_X509SetVersion) then
- Result := _X509SetVersion(x, version)
- else
- Result := 0;
-end;
-
-function X509SetPubkey(x: PX509; pkey: EVP_PKEY): integer;
-begin
- if InitSSLInterface and Assigned(_X509SetPubkey) then
- Result := _X509SetPubkey(x, pkey)
- else
- Result := 0;
-end;
-
-function X509SetIssuerName(x: PX509; name: PX509_NAME): integer;
-begin
- if InitSSLInterface and Assigned(_X509SetIssuerName) then
- Result := _X509SetIssuerName(x, name)
- else
- Result := 0;
-end;
-
-function X509NameAddEntryByTxt(name: PX509_NAME; field: string; _type: integer;
- bytes: string; len, loc, _set: integer): integer;
-begin
- if InitSSLInterface and Assigned(_X509NameAddEntryByTxt) then
- Result := _X509NameAddEntryByTxt(name, PChar(field), _type, PChar(Bytes), len, loc, _set)
- else
- Result := 0;
-end;
-
-function X509Sign(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer;
-begin
- if InitSSLInterface and Assigned(_X509Sign) then
- Result := _X509Sign(x, pkey, md)
- else
- Result := 0;
-end;
-
-function Asn1UtctimeNew: PASN1_UTCTIME;
-begin
- if InitSSLInterface and Assigned(_Asn1UtctimeNew) then
- Result := _Asn1UtctimeNew
- else
- Result := nil;
-end;
-
-procedure Asn1UtctimeFree(a: PASN1_UTCTIME);
-begin
- if InitSSLInterface and Assigned(_Asn1UtctimeFree) then
- _Asn1UtctimeFree(a);
-end;
-
-function X509GmtimeAdj(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME;
-begin
- if InitSSLInterface and Assigned(_X509GmtimeAdj) then
- Result := _X509GmtimeAdj(s, adj)
- else
- Result := nil;
-end;
-
-function X509SetNotBefore(x: PX509; tm: PASN1_UTCTIME): integer;
-begin
- if InitSSLInterface and Assigned(_X509SetNotBefore) then
- Result := _X509SetNotBefore(x, tm)
- else
- Result := 0;
-end;
-
-function X509SetNotAfter(x: PX509; tm: PASN1_UTCTIME): integer;
-begin
- if InitSSLInterface and Assigned(_X509SetNotAfter) then
- Result := _X509SetNotAfter(x, tm)
- else
- Result := 0;
-end;
-
-function i2dX509bio(b: PBIO; x: PX509): integer;
-begin
- if InitSSLInterface and Assigned(_i2dX509bio) then
- Result := _i2dX509bio(b, x)
- else
- Result := 0;
-end;
-
-function i2dPrivateKeyBio(b: PBIO; pkey: EVP_PKEY): integer;
-begin
- if InitSSLInterface and Assigned(_i2dPrivateKeyBio) then
- Result := _i2dPrivateKeyBio(b, pkey)
- else
- Result := 0;
-end;
-
-function EvpGetDigestByName(Name: String): PEVP_MD;
-begin
- if InitSSLInterface and Assigned(_EvpGetDigestByName) then
- Result := _EvpGetDigestByName(PChar(Name))
- else
- Result := nil;
-end;
-
-function Asn1IntegerSet(a: PASN1_INTEGER; v: integer): integer;
-begin
- if InitSSLInterface and Assigned(_Asn1IntegerSet) then
- Result := _Asn1IntegerSet(a, v)
- else
- Result := 0;
-end;
-
-function X509GetSerialNumber(x: PX509): PASN1_INTEGER;
-begin
- if InitSSLInterface and Assigned(_X509GetSerialNumber) then
- Result := _X509GetSerialNumber(x)
- else
- Result := nil;
-end;
-
-// 3DES functions
-procedure DESsetoddparity(Key: des_cblock);
-begin
- if InitSSLInterface and Assigned(_DESsetoddparity) then
- _DESsetoddparity(Key);
-end;
-
-function DESsetkeychecked(key: des_cblock; schedule: des_key_schedule): Integer;
-begin
- if InitSSLInterface and Assigned(_DESsetkeychecked) then
- Result := _DESsetkeychecked(key, schedule)
- else
- Result := -1;
-end;
-
-procedure DESecbencrypt(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer);
-begin
- if InitSSLInterface and Assigned(_DESecbencrypt) then
- _DESecbencrypt(Input, output, ks, enc);
-end;
-
-function LoadLib(const Value: String): HModule;
-begin
- Result := LoadLibrary(Value);
-end;
-
-function GetProcAddr(module: HModule; const ProcName: string): SslPtr;
-begin
- Result := GetProcAddress(module, PChar(ProcName));
-end;
-
-function InitSSLInterface: Boolean;
-{var
- s: string;
- x: integer;}
-begin
- if not IsSSLloaded then
- begin
- SSLLibHandle := LoadLib(DLLSSLName);
- SSLUtilHandle := LoadLib(DLLUtilName);
- {$IFNDEF UNIX}
- if (SSLLibHandle = 0) then
- SSLLibHandle := LoadLib(DLLSSLName2);
- {$ENDIF}
- if (SSLLibHandle <> 0) and (SSLUtilHandle <> 0) then
- begin
- _SslGetError := GetProcAddr(SSLLibHandle, 'SSL_get_error');
- _SslLibraryInit := GetProcAddr(SSLLibHandle, 'SSL_library_init');
- _SslLoadErrorStrings := GetProcAddr(SSLLibHandle, 'SSL_load_error_strings');
- _SslCtxSetCipherList := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_cipher_list');
- _SslCtxNew := GetProcAddr(SSLLibHandle, 'SSL_CTX_new');
- _SslCtxFree := GetProcAddr(SSLLibHandle, 'SSL_CTX_free');
- _SslSetFd := GetProcAddr(SSLLibHandle, 'SSL_set_fd');
- _SslMethodV2 := GetProcAddr(SSLLibHandle, 'SSLv2_method');
- _SslMethodV3 := GetProcAddr(SSLLibHandle, 'SSLv3_method');
- _SslMethodTLSV1 := GetProcAddr(SSLLibHandle, 'TLSv1_method');
- _SslMethodV23 := GetProcAddr(SSLLibHandle, 'SSLv23_method');
- _SslCtxUsePrivateKey := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_PrivateKey');
- _SslCtxUsePrivateKeyASN1 := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_PrivateKey_ASN1');
- //use SSL_CTX_use_RSAPrivateKey_file instead SSL_CTX_use_PrivateKey_file,
- //because SSL_CTX_use_PrivateKey_file not support DER format. :-O
- _SslCtxUsePrivateKeyFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_RSAPrivateKey_file');
- _SslCtxUseCertificate := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate');
- _SslCtxUseCertificateASN1 := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate_ASN1');
- _SslCtxUseCertificateFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate_file');
- _SslCtxUseCertificateChainFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate_chain_file');
- _SslCtxCheckPrivateKeyFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_check_private_key');
- _SslCtxSetDefaultPasswdCb := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_default_passwd_cb');
- _SslCtxSetDefaultPasswdCbUserdata := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_default_passwd_cb_userdata');
- _SslCtxLoadVerifyLocations := GetProcAddr(SSLLibHandle, 'SSL_CTX_load_verify_locations');
- _SslNew := GetProcAddr(SSLLibHandle, 'SSL_new');
- _SslFree := GetProcAddr(SSLLibHandle, 'SSL_free');
- _SslAccept := GetProcAddr(SSLLibHandle, 'SSL_accept');
- _SslConnect := GetProcAddr(SSLLibHandle, 'SSL_connect');
- _SslShutdown := GetProcAddr(SSLLibHandle, 'SSL_shutdown');
- _SslRead := GetProcAddr(SSLLibHandle, 'SSL_read');
- _SslPeek := GetProcAddr(SSLLibHandle, 'SSL_peek');
- _SslWrite := GetProcAddr(SSLLibHandle, 'SSL_write');
- _SslPending := GetProcAddr(SSLLibHandle, 'SSL_pending');
- _SslGetPeerCertificate := GetProcAddr(SSLLibHandle, 'SSL_get_peer_certificate');
- _SslGetVersion := GetProcAddr(SSLLibHandle, 'SSL_get_version');
- _SslCtxSetVerify := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_verify');
- _SslGetCurrentCipher := GetProcAddr(SSLLibHandle, 'SSL_get_current_cipher');
- _SslCipherGetName := GetProcAddr(SSLLibHandle, 'SSL_CIPHER_get_name');
- _SslCipherGetBits := GetProcAddr(SSLLibHandle, 'SSL_CIPHER_get_bits');
- _SslGetVerifyResult := GetProcAddr(SSLLibHandle, 'SSL_get_verify_result');
-
- _X509New := GetProcAddr(SSLUtilHandle, 'X509_new');
- _X509Free := GetProcAddr(SSLUtilHandle, 'X509_free');
- _X509NameOneline := GetProcAddr(SSLUtilHandle, 'X509_NAME_oneline');
- _X509GetSubjectName := GetProcAddr(SSLUtilHandle, 'X509_get_subject_name');
- _X509GetIssuerName := GetProcAddr(SSLUtilHandle, 'X509_get_issuer_name');
- _X509NameHash := GetProcAddr(SSLUtilHandle, 'X509_NAME_hash');
- _X509Digest := GetProcAddr(SSLUtilHandle, 'X509_digest');
- _X509print := GetProcAddr(SSLUtilHandle, 'X509_print');
- _X509SetVersion := GetProcAddr(SSLUtilHandle, 'X509_set_version');
- _X509SetPubkey := GetProcAddr(SSLUtilHandle, 'X509_set_pubkey');
- _X509SetIssuerName := GetProcAddr(SSLUtilHandle, 'X509_set_issuer_name');
- _X509NameAddEntryByTxt := GetProcAddr(SSLUtilHandle, 'X509_NAME_add_entry_by_txt');
- _X509Sign := GetProcAddr(SSLUtilHandle, 'X509_sign');
- _X509GmtimeAdj := GetProcAddr(SSLUtilHandle, 'X509_gmtime_adj');
- _X509SetNotBefore := GetProcAddr(SSLUtilHandle, 'X509_set_notBefore');
- _X509SetNotAfter := GetProcAddr(SSLUtilHandle, 'X509_set_notAfter');
- _X509GetSerialNumber := GetProcAddr(SSLUtilHandle, 'X509_get_serialNumber');
- _EvpPkeyNew := GetProcAddr(SSLUtilHandle, 'EVP_PKEY_new');
- _EvpPkeyFree := GetProcAddr(SSLUtilHandle, 'EVP_PKEY_free');
- _EvpPkeyAssign := GetProcAddr(SSLUtilHandle, 'EVP_PKEY_assign');
- _EVPCleanup := GetProcAddr(SSLUtilHandle, 'EVP_cleanup');
- _EvpGetDigestByName := GetProcAddr(SSLUtilHandle, 'EVP_get_digestbyname');
- _SSLeayversion := GetProcAddr(SSLUtilHandle, 'SSLeay_version');
- _ErrErrorString := GetProcAddr(SSLUtilHandle, 'ERR_error_string_n');
- _ErrGetError := GetProcAddr(SSLUtilHandle, 'ERR_get_error');
- _ErrClearError := GetProcAddr(SSLUtilHandle, 'ERR_clear_error');
- _ErrFreeStrings := GetProcAddr(SSLUtilHandle, 'ERR_free_strings');
- _ErrRemoveState := GetProcAddr(SSLUtilHandle, 'ERR_remove_state');
- _OPENSSLaddallalgorithms := GetProcAddr(SSLUtilHandle, 'OPENSSL_add_all_algorithms_noconf');
- _CRYPTOcleanupAllExData := GetProcAddr(SSLUtilHandle, 'CRYPTO_cleanup_all_ex_data');
- _RandScreen := GetProcAddr(SSLUtilHandle, 'RAND_screen');
- _BioNew := GetProcAddr(SSLUtilHandle, 'BIO_new');
- _BioFreeAll := GetProcAddr(SSLUtilHandle, 'BIO_free_all');
- _BioSMem := GetProcAddr(SSLUtilHandle, 'BIO_s_mem');
- _BioCtrlPending := GetProcAddr(SSLUtilHandle, 'BIO_ctrl_pending');
- _BioRead := GetProcAddr(SSLUtilHandle, 'BIO_read');
- _BioWrite := GetProcAddr(SSLUtilHandle, 'BIO_write');
- _d2iPKCS12bio := GetProcAddr(SSLUtilHandle, 'd2i_PKCS12_bio');
- _PKCS12parse := GetProcAddr(SSLUtilHandle, 'PKCS12_parse');
- _PKCS12free := GetProcAddr(SSLUtilHandle, 'PKCS12_free');
- _RsaGenerateKey := GetProcAddr(SSLUtilHandle, 'RSA_generate_key');
- _Asn1UtctimeNew := GetProcAddr(SSLUtilHandle, 'ASN1_UTCTIME_new');
- _Asn1UtctimeFree := GetProcAddr(SSLUtilHandle, 'ASN1_UTCTIME_free');
- _Asn1IntegerSet := GetProcAddr(SSLUtilHandle, 'ASN1_INTEGER_set');
- _i2dX509bio := GetProcAddr(SSLUtilHandle, 'i2d_X509_bio');
- _i2dPrivateKeyBio := GetProcAddr(SSLUtilHandle, 'i2d_PrivateKey_bio');
-
- // 3DES functions
- _DESsetoddparity := GetProcAddr(SSLUtilHandle, 'DES_set_odd_parity');
- _DESsetkeychecked := GetProcAddr(SSLUtilHandle, 'DES_set_key_checked');
- _DESecbencrypt := GetProcAddr(SSLUtilHandle, 'DES_ecb_encrypt');
- //
- _CRYPTOnumlocks := GetProcAddr(SSLUtilHandle, 'CRYPTO_num_locks');
- _CRYPTOsetlockingcallback := GetProcAddr(SSLUtilHandle, 'CRYPTO_set_locking_callback');
-
-{ SetLength(s, 1024);
- x := GetModuleFilename(SSLLibHandle,PChar(s),Length(s));
- SetLength(s, x);
- SSLLibFile := s;
- SetLength(s, 1024);
- x := GetModuleFilename(SSLUtilHandle,PChar(s),Length(s));
- SetLength(s, x);
- SSLUtilFile := s;}
- //init library
- if assigned(_SslLibraryInit) then
- _SslLibraryInit;
- if assigned(_SslLoadErrorStrings) then
- _SslLoadErrorStrings;
- if assigned(_OPENSSLaddallalgorithms) then
- _OPENSSLaddallalgorithms;
- if assigned(_RandScreen) then
- _RandScreen;
-{$WARNING investigate if it REALLY needs to be done}
-{ if assigned(_CRYPTOnumlocks) and assigned(_CRYPTOsetlockingcallback) then
- InitLocks;}
-
- Result := True;
- SSLloaded := True;
- end
- else
- begin
- //load failed!
- if SSLLibHandle <> 0 then
- begin
- FreeLibrary(SSLLibHandle);
- SSLLibHandle := 0;
- end;
- if SSLUtilHandle <> 0 then
- begin
- FreeLibrary(SSLUtilHandle);
- SSLLibHandle := 0;
- end;
- Result := False;
- end;
- end
- else
- //loaded before...
- Result := true;
-end;
-
-function DestroySSLInterface: Boolean;
-begin
- if IsSSLLoaded then
- begin
-{ //deinit library
- if assigned(_CRYPTOnumlocks) and assigned(_CRYPTOsetlockingcallback) then
- FreeLocks;}
- EVPCleanup;
- CRYPTOcleanupAllExData;
- ErrRemoveState(0);
- end;
- SSLloaded := false;
- if SSLLibHandle <> 0 then
- begin
- FreeLibrary(SSLLibHandle);
- SSLLibHandle := 0;
- end;
- if SSLUtilHandle <> 0 then
- begin
- FreeLibrary(SSLUtilHandle);
- SSLLibHandle := 0;
- end;
-
- _SslGetError := nil;
- _SslLibraryInit := nil;
- _SslLoadErrorStrings := nil;
- _SslCtxSetCipherList := nil;
- _SslCtxNew := nil;
- _SslCtxFree := nil;
- _SslSetFd := nil;
- _SslMethodV2 := nil;
- _SslMethodV3 := nil;
- _SslMethodTLSV1 := nil;
- _SslMethodV23 := nil;
- _SslCtxUsePrivateKey := nil;
- _SslCtxUsePrivateKeyASN1 := nil;
- _SslCtxUsePrivateKeyFile := nil;
- _SslCtxUseCertificate := nil;
- _SslCtxUseCertificateASN1 := nil;
- _SslCtxUseCertificateFile := nil;
- _SslCtxUseCertificateChainFile := nil;
- _SslCtxCheckPrivateKeyFile := nil;
- _SslCtxSetDefaultPasswdCb := nil;
- _SslCtxSetDefaultPasswdCbUserdata := nil;
- _SslCtxLoadVerifyLocations := nil;
- _SslNew := nil;
- _SslFree := nil;
- _SslAccept := nil;
- _SslConnect := nil;
- _SslShutdown := nil;
- _SslRead := nil;
- _SslPeek := nil;
- _SslWrite := nil;
- _SslPending := nil;
- _SslGetPeerCertificate := nil;
- _SslGetVersion := nil;
- _SslCtxSetVerify := nil;
- _SslGetCurrentCipher := nil;
- _SslCipherGetName := nil;
- _SslCipherGetBits := nil;
- _SslGetVerifyResult := nil;
-
- _X509New := nil;
- _X509Free := nil;
- _X509NameOneline := nil;
- _X509GetSubjectName := nil;
- _X509GetIssuerName := nil;
- _X509NameHash := nil;
- _X509Digest := nil;
- _X509print := nil;
- _X509SetVersion := nil;
- _X509SetPubkey := nil;
- _X509SetIssuerName := nil;
- _X509NameAddEntryByTxt := nil;
- _X509Sign := nil;
- _X509GmtimeAdj := nil;
- _X509SetNotBefore := nil;
- _X509SetNotAfter := nil;
- _X509GetSerialNumber := nil;
- _EvpPkeyNew := nil;
- _EvpPkeyFree := nil;
- _EvpPkeyAssign := nil;
- _EVPCleanup := nil;
- _EvpGetDigestByName := nil;
- _SSLeayversion := nil;
- _ErrErrorString := nil;
- _ErrGetError := nil;
- _ErrClearError := nil;
- _ErrFreeStrings := nil;
- _ErrRemoveState := nil;
- _OPENSSLaddallalgorithms := nil;
- _CRYPTOcleanupAllExData := nil;
- _RandScreen := nil;
- _BioNew := nil;
- _BioFreeAll := nil;
- _BioSMem := nil;
- _BioCtrlPending := nil;
- _BioRead := nil;
- _BioWrite := nil;
- _d2iPKCS12bio := nil;
- _PKCS12parse := nil;
- _PKCS12free := nil;
- _RsaGenerateKey := nil;
- _Asn1UtctimeNew := nil;
- _Asn1UtctimeFree := nil;
- _Asn1IntegerSet := nil;
- _i2dX509bio := nil;
- _i2dPrivateKeyBio := nil;
-
- // 3DES functions
- _DESsetoddparity := nil;
- _DESsetkeychecked := nil;
- _DESecbencrypt := nil;
- //
- _CRYPTOnumlocks := nil;
- _CRYPTOsetlockingcallback := nil;
- Result := True;
-end;
-
-function IsSSLloaded: Boolean;
-begin
- Result := SSLLoaded;
-end;
-
-finalization
- DestroySSLInterface;
-
-end.