summaryrefslogtreecommitdiff
path: root/packages/fcl-web/src/cgiapp.pp
diff options
context:
space:
mode:
Diffstat (limited to 'packages/fcl-web/src/cgiapp.pp')
-rw-r--r--packages/fcl-web/src/cgiapp.pp915
1 files changed, 915 insertions, 0 deletions
diff --git a/packages/fcl-web/src/cgiapp.pp b/packages/fcl-web/src/cgiapp.pp
new file mode 100644
index 0000000000..a548923a0a
--- /dev/null
+++ b/packages/fcl-web/src/cgiapp.pp
@@ -0,0 +1,915 @@
+{
+ This file is part of the Free Pascal run time library.
+ Copyright (c) 1999-2000 by the Free Pascal development team
+
+ TCGIApplication class.
+
+ 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.
+
+ **********************************************************************}
+
+{$mode objfpc}
+{$H+}
+
+unit cgiapp;
+
+Interface
+
+uses
+ CustApp,Classes,SysUtils;
+
+Const
+ CGIVarCount = 23;
+
+Type
+ TCGIVarArray = Array[1..CGIVarCount] of String;
+
+Const
+ CgiVarNames : TCGIVarArray =
+ ('AUTH_TYPE',
+ 'CONTENT_LENGTH',
+ 'CONTENT_TYPE',
+ 'GATEWAY_INTERFACE',
+ 'PATH_INFO',
+ 'PATH_TRANSLATED',
+ 'QUERY_STRING', 'REMOTE_ADDR',
+ 'REMOTE_HOST',
+ 'REMOTE_IDENT',
+ 'REMOTE_USER',
+ 'REQUEST_METHOD',
+ 'SCRIPT_NAME',
+ 'SERVER_NAME',
+ 'SERVER_PORT',
+ 'SERVER_PROTOCOL',
+ 'SERVER_SOFTWARE',
+ 'HTTP_ACCEPT',
+ 'HTTP_ACCEPT_CHARSET',
+ 'HTTP_ACCEPT_ENCODING',
+ 'HTTP_IF_MODIFIED_SINCE',
+ 'HTTP_REFERER',
+ 'HTTP_USER_AGENT');
+
+Type
+
+ TCgiApplication = Class(TCustomApplication)
+ Private
+ FResponse : TStream;
+ FEmail : String;
+ FAdministrator : String;
+ FContentTypeEmitted : Boolean;
+ FCGIVars : TCGIVarArray;
+ FRequestVars,
+ FFormFiles : TStrings;
+ Function GetCGIVar (Index : Integer) : String;
+ Procedure InitCGIVars;
+ Procedure InitRequestVars;
+ Procedure InitPostVars;
+ Procedure InitGetVars;
+ Procedure SetContentLength (Value : Integer);
+ Procedure SetCGIVar(Index : Integer; Value : String);
+ Function GetContentLength : Integer;
+ Function GetServerPort : Word;
+ Function GetEmail : String;
+ Function GetAdministrator : String;
+ Procedure ProcessQueryString(Const FQueryString : String);
+ Function GetRequestVariable(Const VarName : String) : String;
+ Function GetRequestVariableCount : Integer;
+ Procedure ProcessURLEncoded(M : TMemoryStream);
+ Procedure ProcessMultiPart(M : TMemoryStream; Const Boundary : String);
+ Public
+ Constructor Create(AOwner : TComponent); override;
+ Destructor Destroy; override;
+ Procedure AddResponse(Const S : String);
+ Procedure AddResponse(Const Fmt : String; Args : Array of const);
+ Procedure AddResponseLn(Const S : String);
+ Procedure AddResponseLn(Const Fmt : String; Args : Array of const);
+ Procedure Initialize; override;
+ Procedure GetCGIVarList(List : TStrings);
+ Procedure GetRequestVarList(List : TStrings);
+ Procedure GetRequestVarList(List : TStrings; NamesOnly : Boolean);
+ Procedure ShowException(E: Exception);override;
+ Procedure DeleteFormFiles;
+ Function EmitContentType : Boolean;
+ Function GetTempCGIFileName : String;
+ Function VariableIsUploadedFile(Const VarName : String) : boolean;
+ Function UploadedFileName(Const VarName : String) : String;
+ Property AuthType : String Index 1 Read GetCGIVar;
+ Property ContentLength : Integer Read GetContentLength Write SetContentLength; // Index 2
+ Property ContentType : String Index 3 Read GetCGIVar Write SetCGIVar;
+ Property GatewayInterface : String Index 4 Read GetCGIVar;
+ Property PathInfo : String index 5 read GetCGIvar;
+ Property PathTranslated : String Index 6 read getCGIVar;
+ Property QueryString : String Index 7 read getcgivar;
+ Property RemoteAddress : String Index 8 read GetCGIVar;
+ Property RemoteHost : String Index 9 read GetCGIVar;
+ Property RemoteIdent : String Index 10 read GetCGIVar;
+ Property RemoteUser : String Index 11 read GetCGIVar;
+ Property RequestMethod : String Index 12 read GetCGIVar;
+ Property ScriptName : String Index 13 read GetCGIVar;
+ Property ServerName : String Index 14 read GetCGIVar;
+ Property ServerPort : Word Read GetServerPort; // Index 15
+ Property ServerProtocol : String Index 16 read GetCGIVar;
+ Property ServerSoftware : String Index 17 read GetCGIVar;
+ Property HTTPAccept : String Index 18 read GetCGIVar;
+ Property HTTPAcceptCharset : String Index 19 read GetCGIVar;
+ Property HTTPAcceptEncoding : String Index 20 read GetCGIVar;
+ Property HTTPIfModifiedSince : String Index 21 read GetCGIVar; // Maybe change to TDateTime ??
+ Property HTTPReferer : String Index 22 read GetCGIVar;
+ Property HTTPUserAgent : String Index 23 read GetCGIVar;
+ Property Email : String Read GetEmail Write FEmail;
+ Property Administrator : String Read GetAdministrator Write FAdministrator;
+ Property RequestVariables[VarName : String] : String Read GetRequestVariable;
+ Property RequestVariableCount : Integer Read GetRequestVariableCount;
+ Property Response : TStream Read FResponse;
+ end;
+
+ResourceString
+ SWebMaster = 'webmaster';
+ SCGIError = 'CGI Error';
+ SAppEncounteredError = 'The application encountered the following error:';
+ SError = 'Error: ';
+ SNotify = 'Notify: ';
+ SErrNoContentLength = 'No content length passed from server!';
+ SErrUnsupportedContentType = 'Unsupported content type: "%s"';
+ SErrNoRequestMethod = 'No REQUEST_METHOD passed from server.';
+ SErrInvalidRequestMethod = 'Invalid REQUEST_METHOD passed from server.';
+
+Implementation
+
+uses
+ iostream;
+
+Type
+ TFormFile = Class(TObject)
+ Private
+ FFileName : String;
+ Public
+ Constructor Create(Const AFileName : String);
+ Property FileName : String Read FFileName Write FFileName;
+ end;
+
+Constructor TFormFile.Create(Const AFileName : String);
+
+begin
+ FFileName:=AFileName;
+end;
+
+{$ifdef cgidebug}
+Var
+ flog : Text;
+
+Procedure Log(Msg : String);
+
+begin
+ Writeln(flog,Msg);
+end;
+
+Procedure Log(Msg : String;Args : Array of const);
+
+begin
+ Writeln(flog,Format(Msg,Args));
+end;
+
+Procedure InitLog;
+
+begin
+ Assign(flog,'/tmp/cgi.log');
+ Rewrite(flog);
+ Log('---- Start of log session ---- ');
+end;
+
+Procedure DoneLog;
+
+begin
+ Close(Flog);
+end;
+{$endif}
+
+Constructor TCgiApplication.Create(AOwner : TComponent);
+
+begin
+ Inherited Create(AOwner);
+ FRequestVars:=TStringList.Create;
+ FFormFiles:=TStringList.Create;
+end;
+
+Destructor TCgiApplication.Destroy;
+
+Var
+ i : Integer;
+
+begin
+ DeleteFormFiles;
+ FFormFiles.Free;
+ FRequestVars.Free;
+ Inherited;
+end;
+
+Function TCgiApplication.GetCGIVar (Index : Integer) : String;
+
+begin
+ Result:=FCGIVars[Index];
+end;
+
+Procedure TCgiApplication.InitCGIVars;
+
+Var
+ I : Integer;
+ L : TStrings;
+
+begin
+ L:=TStringList.Create;
+ Try
+ GetEnvironmentList(L);
+ For I:=1 to CGIVarCount do
+ FCGIVars[i]:=L.Values[CGIVarNames[i]];
+ Finally
+ L.Free;
+ end;
+end;
+
+Function TCgiApplication.GetTempCGIFileName : String;
+
+begin
+ Result:=GetTempFileName('/tmp/','CGI')
+end;
+
+Procedure TCgiApplication.DeleteFormFiles;
+
+Var
+ I,P : Integer;
+ FN : String;
+ FF : TFormFile;
+begin
+ For I:=0 to FFormFiles.Count-1 do
+ begin
+ FF:=TFormFile(FFormFiles.Objects[i]);
+ If Assigned(FF) then
+ begin
+ If FileExists(FF.FileName) then
+ DeleteFile(FF.FileName);
+ FF.Free;
+ end;
+ end;
+end;
+
+Procedure TCgiApplication.Initialize;
+
+begin
+ StopOnException:=True;
+ Inherited;
+ InitCGIVars;
+ InitRequestVars;
+ FResponse:=TIOStream.Create(iosOutput);
+end;
+
+Procedure TCgiApplication.GetCGIVarList(List : TStrings);
+
+Var
+ I : Integer;
+
+begin
+ List.Clear;
+ For I:=1 to cgiVarCount do
+ List.Add(CGIVarNames[i]+'='+FCGIVars[i]);
+end;
+
+Procedure TCgiApplication.GetRequestVarList(List : TStrings);
+
+begin
+ GetRequestVarList(List,False);
+end;
+
+Procedure TCgiApplication.GetRequestVarList(List : TStrings; NamesOnly : Boolean);
+
+Var
+ I,J : Integer;
+ S : String;
+
+begin
+ List.BeginUpdate;
+ Try
+ List.Clear;
+ // Copy one by one, there may be CR/LF in the variables, causing 'Text' to go wrong.
+ If Assigned(FRequestVars) then
+ For I:=0 to FRequestVars.Count-1 do
+ begin
+ S:=FRequestVars[i];
+ If NamesOnly then
+ begin
+ J:=Pos('=',S);
+ If (J>0) then
+ S:=Copy(S,1,J-1);
+ end;
+ List.Add(S);
+ end;
+ finally
+ List.EndUpdate;
+ end;
+end;
+
+
+Function TCgiApplication.GetContentLength : Integer;
+
+begin
+ Result:=StrToIntDef(GetCGIVar(2),-1);
+end;
+
+Procedure TCgiApplication.SetContentLength (Value : Integer);
+
+begin
+ SetCGIVar(2,IntToStr(Value));
+end;
+
+Procedure TCgiApplication.SetCGIVar(Index : Integer; Value : String);
+
+begin
+ If Index in [1..cgiVarCount] then
+ FCGIVars[Index]:=Value;
+end;
+
+
+Function TCgiApplication.GetServerPort : Word;
+begin
+ Result:=StrToIntDef(GetCGIVar(15),0);
+end;
+
+Function TCgiApplication.EmitContentType : Boolean;
+
+Var
+ S: String;
+
+begin
+ Result:=Not FContentTypeEmitted;
+ If result then
+ begin
+ S:=ContentType;
+ If (S='') then
+ S:='text/html';
+ AddResponseLn('Content-Type: '+ContentType);
+ AddResponseLn('');
+ FContentTypeEmitted:=True;
+ end;
+end;
+
+Procedure TCgiApplication.ShowException(E: Exception);
+
+Var
+ TheEmail : String;
+ FrameCount: integer;
+ Frames: PPointer;
+ FrameNumber:Integer;
+
+begin
+ If not FContentTypeEmitted then
+ begin
+ ContentType:='text/html';
+ EmitContentType;
+ end;
+ If (ContentType='text/html') then
+ begin
+ AddResponseLN('<html><head><title>'+Title+': '+SCGIError+'</title></head>');
+ AddResponseLN('<body>');
+ AddResponseLN('<center><hr><h1>'+Title+': ERROR</h1><hr></center><br><br>');
+ AddResponseLN(SAppEncounteredError+'<br>');
+ AddResponseLN('<ul>');
+ AddResponseLN('<li>'+SError+' <b>'+E.Message+'</b>');
+ AddResponseLn('<li> Stack trace:<br>');
+ AddResponseLn(BackTraceStrFunc(ExceptAddr)+'<br>');
+ FrameCount:=ExceptFrameCount;
+ Frames:=ExceptFrames;
+ for FrameNumber := 0 to FrameCount-1 do
+ AddResponseLn(BackTraceStrFunc(Frames[FrameNumber])+'<br>');
+ AddResponseLn('</ul><hr>');
+ TheEmail:=Email;
+ If (TheEmail<>'') then
+ AddResponseLN('<h5><p><i>'+SNotify+Administrator+': <a href="mailto:'+TheEmail+'">'+TheEmail+'</a></i></p></h5>');
+ AddResponseLN('</body></html>');
+ end;
+end;
+
+Function TCgiApplication.GetEmail : String;
+
+Var
+ H : String;
+
+begin
+ If (FEmail='') then
+ begin
+ H:=ServerName;
+ If (H<>'') then
+ Result:=Administrator+'@'+H
+ else
+ Result:='';
+ end
+ else
+ Result:=Email;
+end;
+
+Function TCgiApplication.GetAdministrator : String;
+
+begin
+ If (FADministrator<>'') then
+ Result:=FAdministrator
+ else
+ Result:=SWebMaster;
+end;
+
+Procedure TCgiApplication.InitRequestVars;
+
+var
+ R : String;
+
+begin
+ R:=RequestMethod;
+ if (R='') then
+ Raise Exception.Create(SErrNoRequestMethod);
+ if CompareText(R,'POST')=0 then
+ InitPostVars
+ else if CompareText(R,'GET')=0 then
+ InitGetVars
+ else
+ Raise Exception.CreateFmt(SErrInvalidRequestMethod,[R]);
+end;
+
+Procedure TCgiApplication.ProcessURLEncoded(M : TMemoryStream);
+
+
+var
+ FQueryString : String;
+
+begin
+ SetLength(FQueryString,M.Size); // Skip added Null.
+ M.Read(FQueryString[1],M.Size);
+ ProcessQueryString(FQueryString);
+end;
+
+Type
+ TFormItem = Class(TObject)
+ DisPosition : String;
+ Name : String;
+ isFile : Boolean;
+ FileName : String;
+ ContentType : String;
+ DLen : Integer;
+ Data : String;
+ Procedure Process;
+ end;
+
+Procedure TFormItem.Process;
+
+ Function GetLine(Var S : String) : String;
+
+ Var
+ P : Integer;
+
+ begin
+ P:=Pos(#13#10,S);
+ If (P<>0) then
+ begin
+ Result:=Copy(S,1,P-1);
+ Delete(S,1,P+1);
+ end;
+ end;
+
+ Function GetWord(Var S : String) : String;
+
+ Var
+ I,len : Integer;
+ Quoted : Boolean;
+ C : Char;
+
+ begin
+ len:=length(S);
+ quoted:=false;
+ Result:='';
+ for i:=1 to len do
+ Begin
+ c:=S[i];
+ if (c='"') then
+ Quoted:=Not Quoted
+ else
+ begin
+ if not (c in [' ','=',';',':']) or Quoted then
+ Result:=Result+C;
+ if (c in [';',':','=']) and (not quoted) then
+ begin
+ Delete(S,1,I);
+ Exit;
+ end;
+ end;
+ end;
+ S:='';
+ end;
+
+Var
+ Line : String;
+ Words : TStringList;
+ i,len : integer;
+ c : char;
+ S : string;
+ quoted : boolean;
+
+begin
+ Line:=GetLine(Data);
+ While (Line<>'') do
+ begin
+ S:=GetWord(Line);
+ While (S<>'') do
+ begin
+ If CompareText(S,'Content-Disposition')=0 then
+ Disposition:=GetWord(Line)
+ else if CompareText(S,'name')=0 Then
+ Name:=GetWord(Line)
+ else if CompareText(S,'filename')=0 then
+ begin
+ FileName:=GetWord(Line);
+ isFile:=True;
+ end
+ else if CompareText(S,'Content-Type')=0 then
+ ContentType:=GetWord(Line);
+ S:=GetWord(Line);
+ end;
+ Line:=GetLine(Data);
+ end;
+ // Now Data contains the rest of the data, plus a CR/LF. Strip the CR/LF
+ Len:=Length(Data);
+ If (len>2) then
+ Data:=Copy(Data,1,Len-2);
+end;
+
+Function MakeString(PStart,PEnd : Pchar) : String;
+
+begin
+ SetLength(Result,PEnd-PStart);
+ If Length(Result)>0 then
+ Move(PStart^,Result[1],Length(Result));
+end;
+
+procedure FormSplit(var Cnt : String; boundary: String; List : TList);
+
+// Splits the form into items
+var
+ Sep : string;
+ Clen,slen, p:longint;
+ FI : TFormItem;
+
+begin
+ Sep:='--'+boundary+#13+#10;
+ Slen:=length(Sep);
+ CLen:=Pos('--'+Boundary+'--',Cnt);
+ // Cut last marker
+ Cnt:=Copy(Cnt,1,Clen-1);
+ // Cut first marker
+ Delete(Cnt,1,Slen);
+ Clen:=Length(Cnt);
+ While Clen>0 do
+ begin
+ Fi:=TFormItem.Create;
+ List.Add(Fi);
+ P:=pos(Sep,Cnt);
+ If (P=0) then
+ P:=CLen+1;
+ FI.Data:=Copy(Cnt,1,P-1);
+ delete(Cnt,1,P+SLen-1);
+ CLen:=Length(Cnt);
+ end;
+end;
+
+function GetNextLine(Var Data: String):string;
+
+Var
+ p : Integer;
+
+begin
+ P:=Pos(#13#10,Data);
+ If (P<>0) then
+ begin
+ Result:=Copy(Data,1,P-1);
+ Delete(Data,1,P+1);
+ end;
+end;
+
+Procedure TCgiApplication.ProcessMultiPart(M : TMemoryStream; Const Boundary : String);
+
+Var
+ L : TList;
+ B : String;
+ I,Index : Integer;
+ S,FF,key, Value : String;
+ FI : TFormItem;
+ F : TStream;
+
+begin
+ i:=Pos('=',Boundary);
+ B:=Copy(Boundary,I+1,Length(Boundary)-I);
+ I:=Length(B);
+ If (I>0) and (B[1]='"') then
+ B:=Copy(B,2,I-2);
+ L:=TList.Create;
+ Try
+ SetLength(S,M.Size);
+ If Length(S)>0 then
+ Move(M.Memory^,S[1],M.Size);
+ FormSplit(S,B,L);
+ For I:=L.Count-1 downto 0 do
+ begin
+ FI:=TFormItem(L[i]);
+ FI.Process;
+ If (FI.Name='') then
+ Raise Exception.CreateFmt('Invalid multipart encoding: %s',[FI.Data]);
+ Key:=FI.Name;
+ If Not FI.IsFile Then
+ begin
+ Value:=FI.Data
+ end
+ else
+ begin
+ Value:=FI.FileName;
+ FF:=GetTempCGIFileName;
+ FFormFiles.AddObject(Key,TFormFile.Create(FF));
+ F:=TFileStream.Create(FF,fmCreate);
+ Try
+ if Length(FI.Data)>0 then
+ F.Write(FI.Data[1],Length(FI.Data));
+ finally
+ F.Free;
+ end;
+ FI.Free;
+ L[i]:=Nil;
+ end;
+ FRequestVars.Add(Key+'='+Value)
+ end;
+ Finally
+ For I:=0 to L.Count-1 do
+ TObject(L[i]).Free;
+ L.Free;
+ end;
+end;
+
+Type
+ TCapacityStream = Class(TMemoryStream)
+ Public
+ Property Capacity;
+ end;
+
+Procedure TCgiApplication.InitPostVars;
+
+Var
+ M : TCapacityStream;
+ I : TIOStream;
+ Cl : Integer;
+ B : Byte;
+
+begin
+ CL:=ContentLength;
+ M:=TCapacityStream.Create;
+ Try
+ I:=TIOStream.Create(iosInput);
+ Try
+ if (CL<>0) then
+ begin
+ M.Capacity:=(Cl);
+ M.CopyFrom(I,Cl);
+ end
+ else
+ begin
+ While (I.Read(B,1)>0) do
+ M.Write(B,1)
+ end;
+ Finally
+ I.Free;
+ end;
+ if Pos(ContentType,'MULTIPART/FORM-DATA')=0 then
+ ProcessMultiPart(M,ContentType)
+ else if CompareText(ContentType,'APPLICATION/X-WWW-FORM-URLENCODED')=0 then
+ ProcessUrlEncoded(M)
+ else
+ Raise Exception.CreateFmt(SErrUnsupportedContentType,[ContentType]);
+ finally
+ M.Free;
+ end;
+end;
+
+Procedure TCgiApplication.InitGetVars;
+
+Var
+ FQueryString : String;
+
+begin
+ FQueryString:=QueryString;
+ If (FQueryString<>'') then
+ ProcessQueryString(FQueryString);
+end;
+
+const
+ hexTable = '0123456789ABCDEF';
+
+Procedure TCgiApplication.ProcessQueryString(Const FQueryString : String);
+
+
+var
+ queryItem : String;
+ delimiter : Char;
+ aString : String;
+ aSepStr : String;
+ aPos : Integer;
+ aLenStr : Integer;
+ aLenSep : Integer;
+
+ function hexConverter(h1, h2 : Char) : Char;
+
+ var
+ B : Byte;
+
+ begin
+ B:=(Pos(upcase(h1),hexTable)-1)*16;
+ B:=B+Pos(upcase(h2),hexTable)-1;
+ Result:=chr(B);
+ end;
+
+ procedure Convert_ESC_Chars;
+
+ var
+ index : Integer;
+
+ begin
+ Index:=Length(QueryItem);
+ While (Index>0) do
+ begin
+ If QueryItem[Index]='+' then
+ QueryItem[Index]:=' '
+ else If (QueryItem[Index]='%') and (Index<Length(QueryItem)-1) then
+ begin
+ QueryItem[Index]:=hexConverter(QueryItem[Index+1],QueryItem[index+2]);
+ System.Delete(QueryItem,Index+1,2);
+ end;
+ dec(Index);
+ end;
+ end;
+
+ procedure InitToken(aStr, aSep : String);
+
+ begin
+ aString := aStr;
+ aSepStr := aSep;
+ aPos := 1;
+ aLenStr := Length(aString);
+ aLenSep := Length(aSepStr);
+ end;
+
+ function 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;
+
+
+begin
+ InitToken(FQueryString, '&');
+ while NextToken(QueryItem, delimiter) do
+ begin
+ if (QueryItem<>'') then
+ begin
+ Convert_ESC_Chars;
+ FRequestVars.Add(QueryItem);
+ end;
+ end;
+end;
+
+Function TCGIApplication.GetRequestVariable(Const VarName : String) : String;
+
+begin
+ If Assigned(FRequestVars) then
+ Result:=FRequestVars.Values[VarName];
+end;
+
+Function TCGIApplication.GetRequestVariableCount : Integer;
+
+begin
+ If Assigned(FRequestVars) then
+ Result:=FRequestVars.Count
+ else
+ Result:=0;
+end;
+
+Procedure TCGIApplication.AddResponse(Const S : String);
+
+Var
+ L : Integer;
+
+begin
+ L:=Length(S);
+ If L>0 then
+ FResponse.Write(S[1],L);
+end;
+
+Procedure TCGIApplication.AddResponse(Const Fmt : String; Args : Array of const);
+
+begin
+ AddResponse(Format(Fmt,Args));
+end;
+
+Procedure TCGIApplication.AddResponseLN(Const S : String);
+
+
+begin
+ AddResponse(S+LineEnding);
+end;
+
+Procedure TCGIApplication.AddResponseLN(Const Fmt : String; Args : Array of const);
+
+begin
+ AddResponseLN(Format(Fmt,Args));
+end;
+
+Function TCGIApplication.VariableIsUploadedFile(Const VarName : String) : boolean;
+
+begin
+ Result:=FFormFiles.IndexOf(VarName)<>-1;
+end;
+
+Function TCGIApplication.UploadedFileName(Const VarName : String) : String;
+
+Var
+ FF : TFormFile;
+ i : Integer;
+
+begin
+ Result:='';
+ I:=FFormFiles.IndexOf(VarName);
+ If (I<>-1) then
+ begin
+ FF:=TFormFile(FFormFiles.Objects[i]);
+ If Assigned(FF) then
+ Result:=FF.FileName;
+ end;
+end;
+
+{$ifdef cgidebug}
+Initialization
+ initLog;
+
+Finalization
+ DoneLog;
+{$endif}
+end.