I'm developing my first ISAPI web module with Delphi 11.1 and WebBroker, and want to write logs to the file system. For testing purposes I made the following procedure TryWriteFile
, testing if I can create a file in the WebApplicationDirectory
:
procedure WriteMyFile;
var
fname: string;
fs: TFileStream;
begin
fname := TPath.Combine(WebApplicationDirectory, 'myfile.log');
fs := TFileStream.Create(fname, fmCreate or fmOpenWrite or fmShareDenyNone);
fs.Write([$54,$65,$73,$74,$0D,$0A], 6); { T e s t CR LF }
fs.Free;
end;
Now, I try calling WriteMyFile
in the DefaultHandler action, but get an "access denied" Exception:
procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
WriteMyFile; //==> exception: access denied!
Response.Content := 'no error!';
end;
When I call WriteMyFile
from a separate thread instead, it works. The file is created correctly:
procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
thr: TThread;
begin
//WriteMyFile; //==> exception: access denied!
thr := TThread.CreateAnonymousThread(WriteMyFile); //works, file is created!
thr.FreeOnTerminate := False;
thr.Start;
thr.WaitFor;
thr.Free;
Response.Content := 'no error!';
end;
So my question is: Why? Does it have something to do with Windows folder permissions? And if so, how can those be different in different threads?
IIS configuration:
MYPOOL
C:\inetpub\wwwroot\MYPOOL\
with added "Modify" permission for IIS AppPool\MYPOOL
Both IIS and Delphi 11.1 Alexandria are running on my Windows 10 machine.
I found the culprit: it was an IIS configuration problem. I didn't configure Authentication for my virtual directory (which is a different thing than Authentication for the physical path).
WriteMyFile
always works, regardless of which thread is calling it.The original behavior is still weird, though. But that "just" seems to be an IIS quirk, not related to my code (nor Delphi).
Thank you Peter Wolf for providing a method to confirm this! The default Authentication for my virtual directory was IUSR
, which is exactly, what GetUserName
spits out:
uses Winapi.Windows;
var usrname: string;
procedure GetMyUserName;
var
len: Cardinal;
begin
len := 100;
SetLength(usrname, len);
GetUserNameW(PWideChar(usrname), len);
SetLength(usrname, len);
end;
procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
thr: TThread;
begin
GetMyUserName;
Response.Content := usrname; //==> "IUSR"
thr := TThread.CreateAnonymousThread(WriteMyFile);
thr.FreeOnTerminate := False;
thr.Start;
thr.WaitFor;
thr.Free;
Response.Content := usrname; //==> "MYPOOL"
end;
So apparently, different threads can be associated with different authentication identities.