sp0987 0 Posted August 20 I am writing an HTTP server (TIdHTTPServer) program that services GET requests for images. This 'OnCommandGet ' procedure of Httpserver, calls other procedures to do various tasks, and then finally gets back to the client via TIdHTTPResponseInfo. procedure TVRMEditor.HTTPServerCommandGet(AContext: TIdContext; req: TIdHTTPRequestInfo; res: TIdHTTPResponseInfo); var act, DocExt: string; begin try res.SERVER := 'VRM Editor'; res.ContentType := 'text/html;charset="UTF-8"'; res.ResponseNo := 200; act := UpperCase(copy(req.Document, 2, Length(req.Document) - 1)); DocExt := UpperCase(ExtractFileExt(act)); self.Log(fcomp_name + ': ' + copy(req.RawHTTPCommand, 1, Length(req.RawHTTPCommand) - 9), allowed); -- allowed is a flag to print all the req commands when set to true if DocExt = '.MAX' then begin self.ProcessResponse(req, res); end else self.SendFileToClient(req, res); -- access all the js/css/jpg/css files which are needed to open a web page except on E: Exception do begin self.Log(req.URI + ' : ' + req.Document + sLineBreak + E.ClassName + ' : ' + E.Message); end; end; end; When the Allowed flag is set to true, it prints al the request commands and opens the webpage without any error. If it sets to false, am getting AV / Invalid pointer and couldn't open the page. Am not sure whether you can get the log, but you can see the exceptions. Allowed = true.log Allowed=false.log Share this post Link to post
Kas Ob. 121 Posted August 20 Hi, From what i see, and i am guessing here, that exception is not from this code you pasted, but from one or two different places not shown here: One raised : EInvalidPointer : Invalid pointer operation The other raised EAccessViolation : Access violation at address 0047C27C in module 'VRMEditor.exe'. Read of address FFFFFFFx The second exception does look like managed type variable wrongly or unsafely accessed, in other words it was uninitialized yet there was something trying to access or may be just clean it up, or it could be overwritten on the stack and had corrupted value and the exception was triggered in the hidden part of "end;", (aka clean up) Try to extended logging within self.Log(... itself , there most likely your broken code, track memory corruption too. Share this post Link to post
Remy Lebeau 1414 Posted August 20 (edited) There is no way for us to diagnose the problem with just the log files alone. Clearly there is a problem inside of your Log() or SendFileToClient() methods, but you didn't show any of that code. The Access Violation is telling you the exactly memory address of the code that crashed, 0047C27C. Run the server inside the debugger and jump to that address and see what code is actually running there. On a side note, your OnCommandGet handler is catching and swallowing all exceptions. Don't do that. Indy uses exceptions for error handling, and certain exceptions should be handled by the server itself. For instance, so it knows when to shut down the calling thread when the client disconnects. So, at the very least, you should rethrow any caught exception that derives from EIdException. Edited August 20 by Remy Lebeau Share this post Link to post
sp0987 0 Posted August 21 procedure TVRMEditor.SendFileToClient(req: TIdHTTPRequestInfo; res: TIdHTTPResponseInfo); var doc, ext, Data, fname, err: String; b: boolean; rlst: TStringList; begin Data := ''; fname := req.Document; doc := ExpandFilename(self.RootDir + fname); if not FileExists(doc) then begin self.Log(fcomp_name + ': ' + fname + ' not in editor''s webroot!', LogServer); doc := ExpandFilename(fclirootdir + '\webroot\' + fname); if not FileExists(doc) then begin self.Log(fcomp_name + ': ' + fname + ' not found in any webroot!'); doc := ''; end; end; if doc <> '' then begin ext := UpperCase(ExtractFileExt(fname)); b := (ext = '.CSS') or (ext = '.HTM') or (ext = '.HTML') or (ext = '.JS'); if not b then begin res.ContentType := fMIMEMap.GetFileMIMEType(doc); res.ContentStream := TFileStream.Create(doc, fmOpenRead or fmShareCompat); end else begin try rlst := TStringList.Create; GetConstantGroup('Global_Skin', rlst); Data := LoadDataFromFile(doc); Data := ReplaceAllStringParams(Data, [rlst], '#S', '#', true); if not ReplaceForIncludFiles(Data, err, rlst, true) then self.Log(' #Include Replace Error: ' + err); res.ContentType := fMIMEMap.GetFileMIMEType(doc); res.ContentStream := TStringStream.Create(Data); finally rlst.Free; end; end; end; end; Code to sendfiletoclient Share this post Link to post
Remy Lebeau 1414 Posted August 21 8 hours ago, sp0987 said: Code to sendfiletoclient What about the code for Log()? Since that is the function you were complaining about earlier. Which function exactly is the exception actually being raised in? Share this post Link to post
sp0987 0 Posted August 22 Procedure GLog(Msg: String); var gLogger: TFileLogger = nil; begin if Assigned(gLogger) and Assigned(gLogger.Memo) then begin gLogger.fmLock.Enter; gLogger.Memo.Lines.BeginUpdate; while gLogger.Memo.Lines.Count > 600 do gLogger.Memo.Lines.Delete(0); gLogger.Memo.Lines.Add(Msg); gLogger.Memo.Lines.EndUpdate; gLogger.Memo.Perform(EM_SCROLLCARET, 0, 0); gLogger.fmLock.Leave; end; _Log(Msg); end; Upon my observation, when log prints all the requests from web page, there was no AV/ Invalid pointer Exception. Am not sure that log function was the culprit... Share this post Link to post
Remy Lebeau 1414 Posted August 22 (edited) 4 hours ago, sp0987 said: var gLogger: TFileLogger = nil; begin if Assigned(gLogger) and Assigned(gLogger.Memo) then First, Delphi doesn't allow you to initialize variables in a 'var' block. And second, even if you could, your variable is initialized to nil and not assigned to something else, so the Assigned() checked will ALWAYS return False. But, even if the above was working ok... 4 hours ago, sp0987 said: gLogger.fmLock.Enter; gLogger.Memo.Lines.BeginUpdate; while gLogger.Memo.Lines.Count > 600 do gLogger.Memo.Lines.Delete(0); gLogger.Memo.Lines.Add(Msg); gLogger.Memo.Lines.EndUpdate; gLogger.Memo.Perform(EM_SCROLLCARET, 0, 0); gLogger.fmLock.Leave; TIdHTTPServer is a multi-threaded component, its events are fired in worker threads, and you can't access UI controls directly in worker threads. So, if you are calling Log() in your server's events, then the above code can easily be crashing. You MUST not access UI controls from outside of the main UI thread. Use TThread.Synchronize() or equivalent to run this code block in the UI thread, using a mutex lock is not sufficient. Try this: Procedure GLog(Msg: String); begin if Assigned(gLogger) and Assigned(gLogger.Memo) then begin TThread.Synchronize(nil, procedure begin if Assigned(gLogger) and Assigned(gLogger.Memo) then begin gLogger.Memo.Lines.BeginUpdate; try while gLogger.Memo.Lines.Count > 600 do gLogger.Memo.Lines.Delete(0); gLogger.Memo.Lines.Add(Msg); finally gLogger.Memo.Lines.EndUpdate; end; gLogger.Memo.Perform(EM_SCROLLCARET, 0, 0); end; end); end; _Log(Msg); end; Edited August 22 by Remy Lebeau Share this post Link to post