123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- {
- $Id$
- This file is part of the Free Component Library (FCL)
- Copyright (c) 1999-2000 by Michael Van Canneyt and Florian Klaempfl
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- 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.
- **********************************************************************}
- 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 : Integer;
- aLenStr : Integer;
- aLenSep : Integer;
- 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 : Integer;
- j : Integer;
- BoT : Integer;
- EoT : Integer;
- 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.
- {
- $Log$
- Revision 1.4 2002-09-07 15:15:24 peter
- * old logs removed and tabs fixed
- }
|