program lms_cgi; {$mode objfpc}{$H+} uses Interfaces, Classes, SysUtils, inifiles, httpDefs, fpweb, custweb, custcgi, lnetbase, tcpClient, tcpthreadhelper, extTypes, eventlog; Type { TMyCGIHandler } TMyCGIHandler = Class(TCgiHandler) Private fAnswer: string; fMode: byte; fCode: DWORD; fParam: QWORD; fValues: TStrings; fData: TStream; function answerReady(Sender: TMainThread; const mode: byte; const Code:DWORD; const QValue: QWORD; const Answer: string; const Values: TStrings; const iValues: TParamArray; const Data: TStream): boolean; Public Procedure HandleRequest(ARequest : Trequest; AResponse : TResponse); override; procedure log(ALevel: TLogLevel; Sender: TObject; msg: string); end; { TMyCGIApp } TMyCGIApp = Class(TCustomCGIApplication) private flogFolder: string; fHost: string; fPort: integer; flogger: TEventLog; procedure LoadConfig; Protected function InitializeWebHandler: TWebHandler; override; public constructor CreateWithLogger(AOwner: TComponent); destructor Destroy; override; property Host: string read fHost; property Port: integer read fPort; property LogFolder: string read fLogFolder; property Logger: TEventLog read flogger; end; const aTypes: array[0..3] of string=('"UNKNOWN"','"REQUEST"','"ANSWER"','"ERROR"'); function TMyCGIHandler.answerReady(Sender: TMainThread; const mode: byte; const Code: DWORD; const QValue: QWORD; const Answer: string; const Values: TStrings; const iValues: TParamArray; const Data: TStream ): boolean; begin fAnswer:=Answer; fMode:=mode; fCode:=code; fParam:=QValue; if assigned(Values) then begin fValues:=TStringList.Create; fValues.assign(Values); end; if assigned(Data) then begin fData := TMemoryStream.Create; Data.seek(0,soFromBeginning); fData.CopyFrom(Data,Data.Size); end; Sender.Terminate; end; procedure TMyCGIHandler.HandleRequest(ARequest: Trequest; AResponse: TResponse); var clt: TClientMainThread; i: integer; k,v: string; allfields: TStrings; begin {$IFDEF DEBUG} log(mtDebug,self,'Command '+ARequest.Command); log(mtDebug,self,'RemoteAddr '+ARequest.RemoteAddr); log(mtDebug,self,'RemoteAddress '+ARequest.RemoteAddress); log(mtDebug,self,'CommandLine '+ARequest.CommandLine); log(mtDebug,self,'ContentRange '+ARequest.ContentRange); log(mtDebug,self,'HeaderLine '+ARequest.HeaderLine); log(mtDebug,self,'QueryString '+ARequest.QueryString); log(mtDebug,self,'Authorization '+ARequest.Authorization); log(mtDebug,self,'Connection '+ARequest.Connection); log(mtDebug,self,'WWWAuthenticate '+ARequest.WWWAuthenticate); log(mtDebug,self,'Content '+ARequest.Content); log(mtDebug,self,'ContentType '+ARequest.ContentType); log(mtDebug,self,'From '+ARequest.From); log(mtDebug,self,'UserAgent '+ARequest.UserAgent); log(mtDebug,self,'URI '+ARequest.URI); log(mtDebug,self,'URL '+ARequest.URL); log(mtDebug,self,'ContentEncoding '+ARequest.ContentEncoding); log(mtDebug,self,'ContentLanguage '+ARequest.ContentLanguage); log(mtDebug,self,'Query '+ARequest.Query); log(mtDebug,self,'Location '+ARequest.Location); log(mtDebug,self,'Method '+ARequest.Method); log(mtDebug,self,'PathInfo '+ARequest.PathInfo); log(mtDebug,self,'Referer '+ARequest.Referer); LogStrings(mtInfo, @log,self,'QueryFields',Arequest.QueryFields); LogStrings(mtInfo, @log,self,'ContentFields',Arequest.ContentFields); LogStrings(mtInfo, @log,self,'CookieFields',Arequest.CookieFields); LogStrings(mtInfo, @log,self,'CustomHeaders',Arequest.CustomHeaders); {$ENDIF} if ARequest.QueryFields.Values['action']='cgi-test' then begin AResponse.ContentType := 'text/html'; AResponse.Contents.add('

QueryFields

'); AResponse.Contents.add('
'); for i := 0 to ARequest.QueryFields.Count-1 do begin k := ARequest.QueryFields.Names[i]; v := ARequest.QueryFields.Values[k]; AResponse.Contents.add(format('
%s
%s
',[k,v])); end; AResponse.Contents.add('
'); AResponse.Contents.add(''); AResponse.Contents.add('

ContentFields

'); AResponse.Contents.add('
'); for i := 0 to ARequest.ContentFields.Count-1 do begin k := ARequest.ContentFields.Names[i]; v := ARequest.ContentFields.Values[k]; AResponse.Contents.add(format('
%s
%s
',[k,v])); end; AResponse.Contents.add('
'); AResponse.Contents.add(''); AResponse.SendContent; exit; end; allfields := TStringList.Create; try allfields.AddStrings(ARequest.QueryFields); allfields.AddStrings(ARequest.ContentFields); clt := TClientMainThread.Create(ARequest.QueryFields.Values['action'],allfields,@Log,(Owner as TMyCGIApp).Host,(Owner as TMyCGIApp).Port,@answerReady); clt.start; clt.waitFor; finally allfields.free; end; {$IFDEF DEBUG} log(mtDebug,self,'Data READY'); log(mtDebug,self,'Mode '+ inttostr(fMode)); log(mtDebug,self,'Code '+ inttostr(fCode)); log(mtDebug,self,'Answer '+fAnswer); log(mtDebug,self,'Param '+ inttostr(fParam)); if assigned(fValues) then LogStrings(mtDebug,@log,self,'VALUES',fValues); {$ENDIF} if not assigned(fData) then begin AResponse.ContentType := 'application/json'; AResponse.Contents.add('{'); AResponse.Contents.add('"type":'+aTypes[fMode]+','); AResponse.Contents.add('"code":'+inttostr(fCode)+','); AResponse.Contents.add('"value":'+inttostr(fParam)+','); AResponse.Contents.add('"name":"'+(fAnswer)+'",'); if assigned(fValues) then begin AResponse.Contents.add('"values":['); for i := 0 to fValues.Count-1 do begin AResponse.Contents.Add(fValues[i]+','); end; AResponse.Contents.add(']'); fValues.Free; end; AResponse.Contents.add('}'); end else begin AResponse.FreeContentStream := true; AResponse.ContentType:='application/pdf'; fData.Seek(0,soFromBeginning); AResponse.ContentStream := fData; end; log(mtDebug,self,'Sending'); AResponse.SendContent; log(mtDebug,self,'Sent'); end; procedure TMyCGIHandler.log(ALevel: TLogLevel; Sender: TObject; msg: string); var f: TextFile; s: string; begin if (Owner as TMyCGIApp).Logger=nil then exit; case ALevel of mtError: (Owner as TMyCGIApp).Logger.Error(msg); mtWarning: (Owner as TMyCGIApp).Logger.Warning(msg); mtInfo: (Owner as TMyCGIApp).Logger.Info(msg); mtDebug: (Owner as TMyCGIApp).Logger.Debug(msg); mtExtra: (Owner as TMyCGIApp).Logger.Log(msg); end; end; procedure TMyCGIApp.LoadConfig; var ini: TIniFile; begin ini := TIniFile.Create(ChangeFileExt(ParamStr(0),'.ini')); try fHost := ini.ReadString('PARAMS','host','localhost'); fPort := ini.ReadInteger('PARAMS','port',6543); flogFolder:=ini.ReadString('PARAMS','log',''); finally ini.free; end; end; function TMyCGIApp.InitializeWebHandler: TWebHandler; begin LoadConfig; flogger.FileName:=LogFolder; flogger.Active:=true; flogger.Info('start'); Result:=TMyCgiHandler.Create(self); end; constructor TMyCGIApp.CreateWithLogger(AOwner: TComponent); begin flogger := TEventLog.Create(self); flogger.Identification:='lms_cgi_client'; flogger.LogType:={$IFDEF LINUX}ltSystem{$ELSE}ltFile{$ENDIF}; inherited Create(AOwner); end; destructor TMyCGIApp.Destroy; begin flogger.free; inherited Destroy; end; begin with TMyCGIApp.CreateWithLogger(nil) do try Initialize; Run; finally Free; end; end.