+ Added ezcgi class from Michael Hess

This commit is contained in:
michael 1999-04-27 13:39:50 +00:00
parent 4a5ba69e3c
commit cdc0312666
3 changed files with 442 additions and 0 deletions

392
fcl/inc/ezcgi.pp Normal file
View File

@ -0,0 +1,392 @@
unit ezcgi;
{$mode delphi}
{$H+ }
interface
uses classes, strings, sysutils;
const
hexTable = '0123456789ABCDEF';
type
ECGIException = class(Exception);
TEZcgi = class(TObject)
private
{ Private declarations }
FVariables : TStringList;
FName : String;
FEmail : String;
FQueryString : String;
{ Token variables }
aString : String;
aSepStr : String;
aPos : Byte;
aLenStr : Byte;
aLenSep : Byte;
procedure InitToken(aStr, aSep : String);
function NextToken(var aToken : String; var aSepChar : Char) : Boolean;
procedure GetQueryItems;
procedure ProcessRequest;
procedure LoadEnvVariables;
function GetVal(Index : String) : String;
function GetName(Index : Integer) : String;
function GetVariable(Index : Integer) : String;
function GetVarCount : Integer;
procedure ReadPostQuery;
procedure ReadGetQuery;
protected
{ Protected declarations }
procedure OutputError(errorMessage : String);
public
{ Public declarations }
constructor Create;
destructor Destroy; override;
procedure Run;
procedure WriteContent(ctype : String);
procedure PutLine(sOut : String);
function GetValue(Index : String; defaultValue : String) : String;
procedure DoPost; virtual;
procedure DoGet; virtual;
property Values[Index : String] : String read GetVal;
property Names[Index : Integer] : String read GetName;
property Variables[Index : Integer] : String read GetVariable;
property VariableCount : Integer read GetVarCount;
property Name : String read FName write FName;
property Email : String read FEmail write FEmail;
end;
implementation
{ *********** Include OS-dependent Getenv Call ************ }
{$I ezcgi.inc}
{ *********** Public Methods *************** }
constructor TEZcgi.Create;
begin
FName := 'No name available';
FEmail := 'Email address unavailable';
FVariables := TStringList.Create;
LoadEnvVariables;
end;
destructor TEZcgi.Destroy;
begin
FVariables.Free;
end;
procedure TEZcgi.Run;
begin
ProcessRequest;
end;
procedure TEZcgi.DoPost;
begin
// Must be overriden by child class
end;
procedure TEZcgi.DoGet;
begin
// Must be overriden by child class
end;
procedure TEZcgi.WriteContent(ctype : String);
begin
writeln('Content-Type: ',ctype);
writeln;
end;
procedure TEZcgi.PutLine(sOut : String);
begin
writeln(sOut);
end;
function TEZcgi.GetValue(Index, defaultValue : String) : String;
begin
result := GetVal(Index);
if result = '' then
result := defaultValue;
end;
{ *********** Private Methods *************** }
procedure TEZcgi.LoadEnvVariables;
procedure GetEData(variable : String);
var
tempStr : String;
begin
// This is a system dependent call !!
tempStr := GetEnv(variable);
if tempStr <> '' then
FVariables.Add(variable + '=' + tempStr);
end;
begin
{ Standard CGI Environment Variables }
GetEData('AUTH_TYPE');
GetEData('CONTENT_LENGTH');
GetEData('CONTENT_TYPE');
GetEData('GATEWAY_INTERFACE');
GetEData('PATH_INFO');
GetEData('PATH_TRANSLATED');
GetEData('QUERY_STRING');
GetEData('REMOTE_ADDR');
GetEData('REMOTE_HOST');
GetEData('REMOTE_IDENT');
GetEData('REMOTE_USER');
GetEData('REQUEST_METHOD');
GetEData('SCRIPT_NAME');
GetEData('SERVER_NAME');
GetEData('SERVER_PORT');
GetEData('SERVER_PROTOCOL');
GetEData('SERVER_SOFTWARE');
{ Standard HTTP Environment Variables }
GetEData('HTTP_ACCEPT');
GetEData('HTTP_ACCEPT_CHARSET');
GetEData('HTTP_ACCEPT_ENCODING');
GetEData('HTTP_IF_MODIFIED_SINCE');
GetEData('HTTP_REFERER');
GetEData('HTTP_USER_AGENT');
end;
procedure TEZcgi.ProcessRequest;
var
request : String;
begin
request := GetVal('REQUEST_METHOD');
if request = '' then
OutputError('No REQUEST_METHOD passed from server!')
else if request = 'POST' then
begin
ReadPostQuery;
DoPost;
end
else if request = 'GET' then
begin
ReadGetQuery;
DoGet;
end
else
OutputError('Invalid REQUEST_METHOD passed from server!');
end;
function TEZcgi.GetVal(Index : String) : String;
begin
result := FVariables.Values[Index];
end;
function TEZcgi.GetName(Index : Integer) : String;
begin
result := FVariables.Names[Index];
end;
function TEZcgi.GetVariable(Index : Integer) : String;
begin
result := FVariables[Index];
end;
function TEZcgi.GetVarCount : Integer;
begin
result := FVariables.Count;
end;
procedure TEZcgi.ReadPostQuery;
var
index : Integer;
ch : Char;
temp : String;
code : Word;
contentLength : Integer;
theType : String;
begin
temp := GetVal('CONTENT_LENGTH');
if Length(temp) > 0 then
begin
Val(temp, contentLength, code);
if code <> 0 then
contentLength := 0;
end;
if contentLength = 0 then
OutputError('No content length passed from server!');
theType := UpperCase(GetVal('CONTENT_TYPE'));
if theType <> 'APPLICATION/X-WWW-FORM-URLENCODED' then
OutputError('No content type passed from server!');
FQueryString := '';
for index := 0 to contentLength do
begin
Read(ch);
FQueryString := FQueryString + ch;
end;
GetQueryItems;
end;
procedure TEZcgi.ReadGetQuery;
begin
FQueryString := GetVal('QUERY_STRING');
if FQueryString = '' then
OutputError('No QUERY_STRING passed from server!');
GetQueryItems;
end;
procedure TEZcgi.GetQueryItems;
var
queryItem : String;
delimiter : Char;
function hexConverter(h1, h2 : Char) : Char;
var
thex : byte;
begin
tHex := (Pos(upcase(h1), hexTable) - 1) * 16;
tHex := tHex + Pos(upcase(h2), hexTable) - 1;
result := chr(thex);
end;
procedure Convert_ESC_Chars;
var
index : Integer;
begin
repeat
index := Pos('+', queryItem);
if index > 0 then
queryItem[index] := Chr(32);
until index = 0;
repeat
index := Pos('%', queryItem);
if index > 0 then
begin
queryItem[index] := hexConverter(queryItem[index + 1], queryItem[index + 2]);
system.Delete(queryItem, index + 1, 2);
end;
until index = 0;
end;
begin
InitToken(FQueryString, '&');
while NextToken(queryItem, delimiter) do
begin
if queryItem <> '' then
begin
Convert_ESC_Chars;
FVariables.Add(queryItem);
end;
end;
end;
procedure TEZcgi.OutputError(errorMessage : String);
begin
WriteContent('text/html');
writeln('<html><head><title>CGI ERROR</title></head>');
writeln('<body>');
writeln('<center><hr><h1>CGI ERROR</h1><hr></center><br><br>');
writeln('This CGI application encountered the following error: <br>');
writeln('<ul><br>');
writeln('<li> error: ',errorMessage,'<br><hr>');
writeln('<h5><p><i>Notify ',FName,' <a href="mailto:',FEmail,'">',FEmail,'</a></i></p></h5>');
writeln('</body></html>');
Raise ECGIException.Create(errorMessage);
end;
procedure TEZcgi.InitToken(aStr, aSep : String);
begin
aString := aStr;
aSepStr := aSep;
aPos := 1;
aLenStr := Length(aString);
aLenSep := Length(aSepStr);
end;
function TEZcgi.NextToken(var aToken : String; var aSepChar : Char) : Boolean;
var
i : Byte;
j : Byte;
BoT : Byte;
EoT : Byte;
isSep : Boolean;
begin
BoT := aPos;
EoT := aPos;
for i := aPos to aLenStr do
begin
IsSep := false;
for j := 1 to aLenSep do
begin
if aString[i] = aSepStr[j] then
begin
IsSep := true;
Break;
end;
end;
if IsSep then
begin
EoT := i;
aPos := i + 1;
aSepChar := aString[i];
Break;
end
else
begin
if i = aLenStr then
begin
EoT := i;
aPos := i;
Break;
end;
end;
end;
if aPos < aLenStr then
begin
aToken := Copy(aString, BoT, EoT - BoT);
Result := true;
end
else
begin
if aPos = aLenStr then
begin
aToken := Copy(aString, BoT, EoT - BoT + 1);
Result := true;
aPos := aPos + 1;
end
else
begin
Result := false;
end;
end;
end;
end.

16
fcl/linux/ezcgi.inc Normal file
View File

@ -0,0 +1,16 @@
Uses Linux;
{ Declared EXPLICITLY with Ansistring, so NO mistaking is possible }
Function Getenv (Var EnvVar : AnsiString): AnsiString;
Var P : Pchar;
begin
// Linux version returns pchar.
p:=linux.getenv(EnvVar);
if P<>'' then
getenv:=ansistring(p)
else
getenv:='';
end;

34
fcl/win32/ezcgi.inc Normal file
View File

@ -0,0 +1,34 @@
Uses Windows;
{ Declared EXPLICITLY with Ansistring, so NO mistaking is possible }
{
This function is VERY inefficient, but the downsize would be to
have initialization/finalization code to get/free the environment
settings.
}
Function Getenv (Var EnvVar : AnsiString): AnsiString;
var
s : string;
i : longint;
hp,p : pchar;
begin
getenv:='';
p:=GetEnvironmentStrings;
hp:=p;
while hp^<>#0 do
begin
s:=AnsiString(hp);
i:=pos('=',s);
if upcase(copy(s,1,i-1))=upcase(envvar) then
begin
getenv:=copy(s,i+1,length(s)-i);
break;
end;
{ next string entry}
hp:=hp+strlen(hp)+1;
end;
FreeEnvironmentStrings(p);
end;