program testcgiapp; {$mode objfpc}{$H+} uses Classes, SysUtils, CustApp, inifiles, process, httpdefs,custcgi { you can add units after this }; type { TTestCGIApplication } TTestCGIApplication = class(TCustomApplication) private FCGB: String; FCGIE: TStrings; FCGV: TStrings; FMethod: String; Foutput: String; FPostData: String; FPathInfo : String; FScriptName: String; FURL: String; procedure CheckEnvironment; procedure CheckMethod; procedure ProcessConfig; procedure RunCGI; protected Property CGIEnvironment : TStrings Read FCGIE Write FCGIE; Property URL : String Read FURL Write FURL; Property PostData : String Read FPostData Write FPostData; Property Method : String Read FMethod Write FMethod; Property CGIOutput : String Read Foutput Write FOutput; Property CGIBinary : String Read FCGB Write FCGB; Property CGIVariables : TStrings Read FCGV Write FCGV; Property PathInfo : String Read FPathInfo Write FPathInfo; Property ScriptName : String Read FScriptName Write FScriptName; procedure DoRun; override; public constructor Create(TheOwner: TComponent); override; Destructor Destroy; override; procedure WriteHelp; virtual; end; { TTestCGIApplication } Resourcestring SErrUnsupportedMethod = 'Unsupported method: "%s"'; SErrNoCGIBinary = 'No CGI binary specified'; Const SConfig = 'Config'; KeyURL = 'URL'; KeyEnvironment = 'Environment'; KeyMethod = 'Method'; KeyPost = 'PostData'; SEnvironment = KeyEnvironment; SVariables = 'Variables'; procedure TTestCGIApplication.ProcessConfig; Var Ini : TInifile; S : String; begin Ini:=TIniFile.Create(GetOptionValue('c','config')); try With Ini do begin URL:=ReadString(SConfig,KeyURL,''); S:=ReadString(SConfig,KeyEnvironment,''); If (S<>'') and FileExists(S) then CGIEnvironment.LoadFromFile(S); If SectionExists(SEnvironment) then ReadSectionValues(SEnvironment,CGIEnvironment); If SectionExists(SVariables) then ReadSectionValues(SVariables,CGIVariables); If (Method='') then Method:=ReadString(SConfig,KeyMethod,'GET'); PostData:=ReadString(SConfig,KeyPost,''); end; finally Ini.Free; end; end; procedure TTestCGIApplication.RunCGI; Var Proc : TProcess; begin If (CGIBinary='') then Raise Exception.Create(SerrNoCGIBinary); Proc:=TProcess.Create(Self); try Proc.CommandLine:=CGIBinary; Proc.Environment:=CGIEnvironment; Proc.Execute; finally Proc.Free; end; end; procedure TTestCGIApplication.CheckMethod; begin If (Method='') then Method:='GET' else begin Method:=Uppercase(Method); end; end; (* ({ 1: 'AUTH_TYPE' } fieldWWWAuthenticate, // ? { 2: 'CONTENT_LENGTH' } FieldContentLength, { 3: 'CONTENT_TYPE' } FieldContentType, { 4: 'GATEWAY_INTERFACE' } '', { 5: 'PATH_INFO' } '', { 6: 'PATH_TRANSLATED' } '', { 7: 'QUERY_STRING' } '', { 8: 'REMOTE_ADDR' } '', { 9: 'REMOTE_HOST' } '', { 10: 'REMOTE_IDENT' } '', { 11: 'REMOTE_USER' } '', { 12: 'REQUEST_METHOD' } '', { 13: 'SCRIPT_NAME' } '', { 14: 'SERVER_NAME' } '', { 15: 'SERVER_PORT' } '', { 16: 'SERVER_PROTOCOL' } '', { 17: 'SERVER_SOFTWARE' } '', { 18: 'HTTP_ACCEPT' } FieldAccept, { 19: 'HTTP_ACCEPT_CHARSET' } FieldAcceptCharset, { 20: 'HTTP_ACCEPT_ENCODING' } FieldAcceptEncoding, { 21: 'HTTP_IF_MODIFIED_SINCE' } FieldIfModifiedSince, { 22: 'HTTP_REFERER' } FieldReferer, { 23: 'HTTP_USER_AGENT' } FieldUserAgent, { 24: 'HTTP_COOKIE' } FieldCookie, // Additional Apache vars { 25: 'HTTP_CONNECTION' } FieldConnection, { 26: 'HTTP_ACCEPT_LANGUAGE' } FieldAcceptLanguage, { 27: 'HTTP_HOST' } '', { 28: 'SERVER_SIGNATURE' } '', { 29: 'SERVER_ADDR' } '', { 30: 'DOCUMENT_ROOT' } '', { 31: 'SERVER_ADMIN' } '', { 32: 'SCRIPT_FILENAME' } '', { 33: 'REMOTE_PORT' } '', { 34: 'REQUEST_URI' } '', { 35: 'CONTENT' } '', { 36: 'XHTTPREQUESTEDWITH' } '' *) procedure TTestCGIApplication.CheckEnvironment; Var L : TStrings; S,N,V : String; I : Integer; begin L:=CGIEnvironment; If L.IndexOfName('REQUEST_METHOD')=-1 then L.Values['REQUEST_METHOD']:=Method; S:=ScriptName; If (S='') then S:=CGIBinary; If L.IndexOfName('SCRIPT_NAME')=-1 then L.Values['SCRIPT_NAME']:=S; If L.IndexOfName('SCRIPT_FILENAME')=-1 then L.Values['SCRIPT_FILENAME']:=S; If (PathInfo<>'') then L.Values['PATH_INFO']:=PathInfo; If (Method='GET') then begin If L.IndexOfName('QUERY_STRING')=-1 then begin S:=''; If (CGIVariables.Count>0) then For I:=0 to CGIVariables.Count-1 do begin CGIVariables.GetNameValue(I,N,V); If (S<>'') then S:=S+'&'; S:=S+N+'='+HTTPEncode(V); end; L.Add('QUERY_STRING='+S) end; end end; procedure TTestCGIApplication.DoRun; var ErrorMsg: String; begin // parse parameters if HasOption('h','help') then begin WriteHelp; Terminate; Exit; end; if HasOption('c','config') then ProcessConfig; If HasOption('u','url') then URL:=GetOptionValue('u','url'); If HasOption('e','environment') then CGIEnvironment.LoadFromFile(GetOptionValue('e','environment')); If HasOption('o','output') then CGIOutput:=GetOptionValue('o','output'); If HasOption('m','method') then Method:=GetOptionValue('m','method'); If HasOption('p','pathinfo') then PathInfo:=GetOptionValue('p','pathinfo'); If HasOption('s','scriptname') then ScriptName:=GetOptionValue('s','scriptname'); If HasOption('r','variables') then CGIOutput:=GetOptionValue('v','variables'); If HasOption('i','input') then CGIBinary:=GetOptionValue('i','input'); CheckMethod; CheckEnvironment; RunCGI; { add your program here } // stop program loop Terminate; end; constructor TTestCGIApplication.Create(TheOwner: TComponent); begin inherited Create(TheOwner); StopOnException:=True; FCGIE:=TStringList.Create; FCGV:=TStringList.Create; end; destructor TTestCGIApplication.Destroy; begin FreeAndNil(FCGIE); FreeAndNil(FCGV); inherited Destroy; end; procedure TTestCGIApplication.WriteHelp; begin Writeln('Usage: ',ExeName,' [options]'); Writeln('Where options is one of : '); Writeln(' -h this help'); Writeln(' -c|--config=file use file for configuration'); Writeln(' -e|--environment=file use file for CGI environment (overrides config).'); Writeln(' -i|--input=file use file as CGI binary.'); Writeln(' -m|--method=method use method to invoke CGI (overrides config, default is GET).'); Writeln(' -o|--output=file use file for CGI output (overrides config).'); Writeln(' -p|--pathinfo=path use path for PATH_INFO environment variable (overrides config).'); Writeln(' -r|--variables=file read query variables from file (overrides config).'); Writeln(' -u|--url=URL use URL as the URL (overrides config).'); end; var Application: TTestCGIApplication; begin Application:=TTestCGIApplication.Create(nil); Application.Title:='Test CGI application'; Application.Run; Application.Free; end.