home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Runimage / Delphi50 / Source / Internet / NSTOIS.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-08-11  |  25.3 KB  |  860 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {       NSAPI to ISAPI server application components    }
  6. {                                                       }
  7. {       Copyright (c) 1997,99 Inprise Corporation       }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit NSToIS;
  12.  
  13. interface
  14.  
  15. uses SysUtils, Windows, Classes, ISAPI2, NSAPI,
  16.   {$IFDEF NETSCAPE3}
  17.   NS30Fix,
  18.   {$ENDIF}
  19.   {$IFDEF NETSCAPE35}
  20.   NS35Fix,
  21.   {$ENDIF}
  22.   {$IFDEF NETSCAPE36}
  23.   NS36Fix,
  24.   {$ENDIF}
  25.   SyncObjs;
  26.  
  27. type
  28.   TISAPIApplicationList = class;
  29.  
  30.   TISAPIApplication = class
  31.   private
  32.     FModule: THandle;
  33.     FFileName: string;
  34.     FVersionInfo: THSE_VERSION_INFO;
  35.     FOwner: TISAPIApplicationList;
  36.   public
  37.     GetExtensionVersion: TGetExtensionVersion;
  38.     HTTPExtensionProc: THTTPExtensionProc;
  39.     TerminateExtension: TTerminateExtension;
  40.     constructor Create(AOWner: TISAPIApplicationList; const AFileName: string);
  41.     destructor Destroy; override;
  42.  
  43.     procedure Load;
  44.     procedure Unload(Ask: Boolean);
  45.  
  46.     property VersionInfo: THSE_VERSION_INFO read FVersionInfo;
  47.   end;
  48.  
  49.   EISAPIException = class(Exception);
  50.  
  51.   TISAPISession = class
  52.   private
  53.     { ISAPI Interface }
  54.     FECB: TEXTENSION_CONTROL_BLOCK;
  55.     FISAPIApplication: TISAPIApplication;
  56.     FPathTranslated: string;
  57.     { NSAPI Interface }
  58.     Fpb: PPblock;
  59.     Fsn: PSession;
  60.     Frq: PRequest;
  61.     Fenv: PPCharArray;
  62.     { HSE_REQ_DONE_WITH_SESSION event }
  63.     FEvent: TEvent; 
  64.  
  65.     { ISAPI Service functions }
  66.     function GetServerVariable(VariableName: PChar; Buffer: Pointer; var Size: DWORD): Boolean;
  67.     function WriteClient(Buffer: Pointer; var Bytes: DWORD): Boolean;
  68.     function ReadClient(Buffer: Pointer; var Size: DWORD): Boolean;
  69.     function ServerSupportFunction(HSERequest: DWORD; Buffer: Pointer;
  70.       Size: LPDWORD; DataType: LPDWORD): Boolean;
  71.   public
  72.     constructor Create(pb: PPblock; sn: PSession; rq: PRequest;
  73.       ISAPIApplication: TISAPIApplication);
  74.     destructor Destroy; override;
  75.     procedure ProcessExtension;
  76.   end;
  77.  
  78.   TISAPIApplicationList = class
  79.   private
  80.     FList: TList;
  81.     FCriticalSection: TCriticalSection;
  82.     FLogfd: SYS_FILE;
  83.     procedure AddApplication(ISAPIApplication: TISAPIApplication);
  84.     procedure ClearApplications;
  85.     function FindApplication(const AFileName: string): TISAPIApplication;
  86.     procedure RemoveApplication(ISAPIApplication: TISAPIApplication);
  87.   public
  88.     constructor Create;
  89.     destructor Destroy; override;
  90.     function LoadApplication(const AFileName: string): TISAPIApplication;
  91.     function InitLog(pb: PPblock; sn: PSession; rq: Prequest): Integer;
  92.     procedure LogMessage(const Fmt: string; Params: array of const);
  93. {    function NewSession(ISAPIApplication: TISAPIApplication; pb: PPBlock;
  94.       sn: PSession; rq: PRequest): TISAPISession;}
  95.   end;
  96.  
  97. var
  98.   ISAPIApplicationList: TISAPIApplicationList = nil;
  99.  
  100. procedure LogMessage(const Fmt: string; Params: array of const);
  101. function UnixPathToDosPath(const Path: string): string;
  102. function DosPathToUnixPath(const Path: string): string;
  103. procedure InitISAPIApplicationList;
  104. procedure DoneISAPIAPplicationList;
  105.  
  106. implementation
  107.  
  108. resourcestring
  109.   sInvalidISAPIApp = 'Invalid ISAPI application: %s';
  110.   sUnSupportedISAPIApp = 'Unsupported ISAPI Application version: %.8x';
  111.   sGEVFailed = 'Call to GetExtensionVersion FAILED. Error Code: %d';
  112.   sErrorLoadingISAPIApp = 'Error loading ISAPI Application: %s';
  113.   sInvalidRedirectParam = 'Invalid Redirect parameter';
  114.   sISAPIAppError = 'ISAPI Application Error';
  115.  
  116. function TranslateChar(const Str: string; FromChar, ToChar: Char): string;
  117. var
  118.   I: Integer;
  119. begin
  120.   Result := Str;
  121.   for I := 1 to Length(Result) do
  122.     if Result[I] = FromChar then
  123.       Result[I] := ToChar
  124.     else if Result[I] = '?' then Break;
  125. end;
  126.  
  127. function UnixPathToDosPath(const Path: string): string;
  128. begin
  129.   Result := TranslateChar(Path, '/', '\');
  130. end;
  131.  
  132. function DosPathToUnixPath(const Path: string): string;
  133. begin
  134.   Result := TranslateChar(Path, '\', '/');
  135. end;
  136.  
  137. procedure LogMessage(const Fmt: string; Params: array of const);
  138. begin
  139.   ISAPIApplicationList.LogMessage(Fmt, Params);
  140. end;
  141.  
  142. { TISAPIApplication }
  143.  
  144. constructor TISAPIApplication.Create(AOwner: TISAPIApplicationList;
  145.   const AFileName: string);
  146. begin
  147.   FFileName := AFileName;
  148.   FOwner := AOwner;
  149.   FOwner.AddApplication(Self);
  150.   Load;
  151. end;
  152.  
  153. destructor TISAPIApplication.Destroy;
  154. begin
  155.   Unload(False);
  156.   FOwner.RemoveApplication(Self);
  157.   inherited Destroy;
  158. end;
  159.  
  160. procedure TISAPIApplication.Load;
  161. var
  162.   ErrorMode: Integer;
  163. begin
  164.   ErrorMode := SetErrorMode(SEM_NOOPENFILEERRORBOX);
  165.   try
  166.     FModule := LoadLibrary(PChar(FFileName));
  167.     if FModule <> 0 then
  168.     begin
  169.       @GetExtensionVersion := GetProcAddress(FModule, 'GetExtensionVersion');
  170.       @HTTPExtensionProc := GetProcAddress(FModule, 'HttpExtensionProc');
  171.       @TerminateExtension := GetProcAddress(FModule, 'TerminateExtension');
  172.       if not Assigned(GetExtensionVersion) or not Assigned(HTTPExtensionProc) then
  173.         raise EISAPIException.CreateResFmt(@sInvalidISAPIApp, [FFileName]);
  174.       if GetExtensionVersion(FVersionInfo) then
  175.       begin
  176.         LogMessage('%s: Version: $%.8x'#13#10, [FFileName, FVersionInfo.dwExtensionVersion]);
  177.         if (HiWord(FVersionInfo.dwExtensionVersion) <> $0001) and
  178.           (HiWord(FVersionInfo.dwExtensionVersion) <> $0002) then
  179.           raise EISAPIException.CreateResFmt(@sUnsupportedISAPIApp,
  180.             [FVersionInfo.dwExtensionVersion]);
  181.       end else
  182.         raise EISAPIException.CreateResFmt(@sGEVFailed, [GetLastError]);
  183.     end else
  184.       raise EISAPIException.CreateResFmt(@sErrorLoadingISAPIApp, [FFileName]);
  185.   finally
  186.     SetErrorMode(ErrorMode);
  187.   end;
  188. end;
  189.  
  190. procedure TISAPIApplication.Unload(Ask: Boolean);
  191. const
  192.   HSE_TERM: array[Boolean] of DWORD = (HSE_TERM_ADVISORY_UNLOAD, HSE_TERM_MUST_UNLOAD);
  193. var
  194.   CanUnload: Boolean;
  195. begin
  196.   if FModule > 32 then
  197.   begin
  198.     CanUnload := True;
  199.     if Assigned(TerminateExtension) then
  200.       CanUnload := not Ask or TerminateExtension(HSE_TERM[Ask]);
  201.     if CanUnload and FreeLibrary(FModule) then
  202.       FModule := 0;
  203.   end;
  204. end;
  205.  
  206. function GetServerVariableProc(ConnID: HConn; VariableName: PChar;
  207.   Buffer: Pointer; var Size: DWORD): BOOL; stdcall;
  208. begin
  209.   if ConnID <> 0 then
  210.     Result := TISAPISession(ConnID).GetServerVariable(VariableName, Buffer, Size)
  211.   else
  212.   begin
  213.     Result := False;
  214.     SetLastError(ERROR_INVALID_PARAMETER);
  215.   end;
  216. end;
  217.  
  218. function WriteClientProc(ConnID: HConn; Buffer: Pointer; var Bytes: DWORD;
  219.   dwReserved: DWORD): BOOL; stdcall;
  220. begin
  221.   if ConnID <> 0 then
  222.     Result := TISAPISession(ConnID).WriteClient(Buffer, Bytes)
  223.   else
  224.   begin
  225.     Result := False;
  226.     SetLastError(ERROR_INVALID_PARAMETER);
  227.   end;
  228. end;
  229.  
  230. function ReadClientProc(ConnID: HConn; Buffer: Pointer;
  231.   var Size: DWORD): BOOL; stdcall;
  232. begin
  233.   if ConnID <> 0 then
  234.     Result := TISAPISession(ConnID).ReadClient(Buffer, Size)
  235.   else
  236.   begin
  237.     Result := False;
  238.     SetLastError(ERROR_INVALID_PARAMETER);
  239.   end;
  240. end;
  241.  
  242. function ServerSupportProc(ConnID: HConn; HSERequest: DWORD; Buffer: Pointer;
  243.   Size: LPDWORD; DataType: LPDWORD): BOOL; stdcall;
  244. begin
  245.   if ConnID <> 0 then
  246.     Result := TISAPISession(ConnID).ServerSupportFunction(HSERequest, Buffer,
  247.       Size, DataType)
  248.   else
  249.   begin
  250.     Result := False;
  251.     SetLastError(ERROR_INVALID_PARAMETER);
  252.   end;
  253. end;
  254.  
  255. function MakeValid(Str: PChar): PChar;
  256. begin
  257.   if Str = nil then
  258.     Result := ''
  259.   else Result := Str;
  260. end;
  261.  
  262. const
  263.   DocumentMoved =
  264.     '<head><title>Document moved</title></head>' +
  265.     '<body><h1>Object Moved</h1>' +
  266.     'This document may be found <a HREF="%s">here</a></body>'#13#10;
  267.  
  268. // Diagnostic purposes only... Do not resource these strings    
  269. function GetObjectConfig(os: PHttpdObjSet): string;
  270. var
  271.   obj: PHttpdObject;
  272.   dt: PDtable;
  273.   dir: PDirective;
  274.   I, J, K: Integer;
  275. begin
  276.   Result := Format('os: $%p'#13#10, [os]);
  277.   try
  278.     if os <> nil then
  279.     begin
  280.       K := 0;
  281.       obj := PPointerList(os.obj)^[K];
  282.       Result := Format('%sobj: $%p'#13#10, [Result, obj]);
  283.       if obj <> nil then
  284.       begin
  285.         while obj <> nil do
  286.         begin
  287.           Result := Format('%sobj.name: $%p'#13#10, [Result, obj.name]);
  288.           Result := Format('%sRoot Object: %s (%s)'#13#10, [Result, 'default',
  289.             NSstr2String(pblock_pblock2str(obj.name, nil))]);
  290.           dt := obj.dt;
  291.           Result := Format('%sobj.dt: $%p'#13#10'obj.nd: %d'#13#10, [Result, dt, obj.nd]);
  292.           for I := 0 to obj.nd - 1 do
  293.           begin
  294.             dir := dt.inst;
  295.             Result := Format('%sdt.inst: $%p'#13#10'dt.ni: %d'#13#10, [Result, dir, dt.ni]);
  296.             for J := 0 to dt.ni - 1 do
  297.             begin
  298.               if dir <> nil then
  299.               begin
  300.                 if dir.param <> nil then
  301.                   Result := Format('%s  Param: %s'#13#10, [Result,
  302.                     NSstr2String(pblock_pblock2str(dir.param, nil))])
  303.                 else Result := Format('%s  Param:'#13#10, [Result]);
  304.                 if dir.client <> nil then
  305.                   Result := Format('%s  Client: %s'#13#10, [Result,
  306.                     NSstr2String(pblock_pblock2str(dir.client, nil))])
  307.                 else Result := Format('%s  Client:'#13#10, [Result]);
  308.               end;
  309.               Inc(dir);
  310.             end;
  311.             Inc(dt);
  312.           end;
  313.           Inc(K);
  314.           obj := PPointerList(os.obj)^[K];
  315.         end;
  316.       end else Result := 'root_object not found';
  317.     end else Result := 'std_os Objset not found';
  318.   except
  319.     on E: Exception do
  320.       Result := Format('%sException %s: %s'#13#10, [Result, E.ClassName, E.Message]);
  321.   end;
  322. end;
  323.  
  324. { TISAPISession }
  325.  
  326. constructor TISAPISession.Create(pb: PPblock; sn: PSession; rq: PRequest;
  327.   ISAPIApplication: TISAPIApplication);
  328. var
  329.   Temp: PChar;
  330. begin
  331.   Fpb := pb;
  332.   Fsn := sn;
  333.   Frq := rq;
  334.   FISAPIApplication := ISAPIApplication;
  335.   FEvent := TSimpleEvent.Create;
  336.   with FECB do
  337.   begin
  338.     cbSize := SizeOf(FECB);
  339.     dwVersion := MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
  340.     ConnID := THandle(Self);
  341.     lpszMethod := MakeValid(pblock_findval('method', rq.reqpb));
  342.     lpszQueryString := MakeValid(pblock_findval('query', rq.reqpb));
  343.     lpszPathInfo := MakeValid(pblock_findval('path-info', rq.vars));
  344.     FPathTranslated := UnixPathToDosPath(NSstr2String(
  345.       pblock_findval('path-translated', rq.vars)));
  346.     lpszPathTranslated := PChar(FPathTranslated);
  347.     lpszContentType := MakeValid(pblock_findval('content-type', rq.headers));
  348.     Temp := pblock_findval('content-length', rq.headers);
  349.     try
  350.       cbTotalBytes := StrToIntDef(MakeValid(Temp), 0);
  351.     finally
  352.       system_free(Temp);
  353.     end;
  354.     with Fsn.inbuf^ do
  355.     begin
  356.       while (inbuf[pos] in [#13,#10]) and (pos < cursize) do Inc(pos);
  357.       cbAvailable := cursize - pos;
  358.       if cbTotalBytes < cbAvailable then
  359.         cbTotalBytes := cbAvailable;
  360.       GetMem(lpbData, cbAvailable);
  361.       Move(inbuf[pos], lpbData^, cbAvailable);
  362.     end;
  363.     GetServerVariable := GetServerVariableProc;
  364.     WriteClient := WriteClientProc;
  365.     ReadClient := ReadClientProc;
  366.     ServerSupportFunction := ServerSupportProc;
  367.   end;
  368. end;
  369.  
  370. destructor TISAPISession.Destroy;
  371.  
  372.   procedure FreeStr(Str: PChar);
  373.   begin
  374.     if (Str <> nil) and (Str^ <> #0) then
  375.       system_free(Str);
  376.   end;
  377.  
  378. begin
  379.   with FECB do
  380.   begin
  381.     FreeStr(lpszMethod);
  382.     FreeStr(lpszQueryString);
  383.     FreeStr(lpszPathInfo);
  384.     FreeStr(lpszContentType);
  385.     FreeMem(lpbData);
  386.   end;
  387.   if Fenv <> nil then util_env_free(Fenv);
  388.   FEvent.Free;
  389.   inherited Destroy;
  390. end;
  391.  
  392. function TISAPISession.GetServerVariable(VariableName: PChar; Buffer: Pointer;
  393.   var Size: DWORD): Boolean;
  394. var
  395.   HeaderName: string;
  396.   HeaderValue: PChar;
  397.  
  398.   procedure InitEnv;
  399.   var
  400.     Value: PChar;
  401.  
  402.     procedure AddToEnv(var Env: PPCharArray; Name, Value: PChar);
  403.     var
  404.       Pos: Integer;
  405.     begin
  406.       Env := util_env_create(Env, 1, Pos);
  407.       Env[Pos] := util_env_str(Name, Value);
  408.       Env[Pos+1] := nil;
  409.     end;
  410.  
  411.   begin
  412.     if Fenv = nil then
  413.     begin
  414.       Fenv := http_hdrs2env(Frq.headers);
  415.       Value := pblock_findval('content-length', Frq.headers);
  416.       try
  417.         if Value <> nil then
  418.           AddToEnv(Fenv, 'HTTP_CONTENT_LENGTH', Value);
  419.       finally
  420.         system_free(Value);
  421.       end;
  422.       Value := pblock_findval('content-type', Frq.headers);
  423.       try
  424.         if Value <> nil then
  425.           AddToEnv(Fenv, 'HTTP_CONTENT_TYPE', Value);
  426.       finally
  427.         system_free(Value);
  428.       end;
  429.       Value := pblock_findval('authorization', Frq.headers);
  430.       try
  431.         if Value <> nil then
  432.           AddToEnv(Fenv, 'HTTP_AUTHORIZATION', Value);
  433.       finally
  434.         system_free(Value);
  435.       end;
  436.     end;
  437.   end;
  438.  
  439.   procedure CopyValue(Value: PChar; var Result: Boolean);
  440.   begin
  441.     Result := False;
  442.     PChar(Buffer)[0] := #0;
  443.     if Value <> nil then
  444.     begin
  445.       StrLCopy(Buffer, Value, Size);
  446.       if Size < StrLen(Value) then
  447.         SetLastError(ERROR_INSUFFICIENT_BUFFER)
  448.       else Result := True;
  449.       Size := StrLen(Value) + 1;
  450.     end else SetLastError(ERROR_NO_DATA);
  451.   end;
  452.  
  453.   function AllHeaders: string;
  454.   var
  455.     P: PPCharArray;
  456.     I: Integer;
  457.   begin
  458.     InitEnv;
  459.     P := Fenv;
  460.     Result := '';
  461.     I := 0;
  462.     while P^[I] <> nil do
  463.     begin
  464.       Result := Format('%s%s'#13#10, [Result, TranslateChar(P^[I], '=', ':')]);
  465.       Inc(I);
  466.     end;
  467.   end;
  468.  
  469. begin
  470.   // Check if this is a request for an HTTP header
  471.   if VariableName = nil then VariableName := 'BAD';
  472.   LogMessage('GetServerVariable(%s, $%p, %d)'#13#10, [VariableName, Buffer, Size]);
  473.   HeaderValue := nil;
  474.   HeaderName := VariableName;
  475.   if shexp_casecmp(VariableName, 'HTTP_*') = 0 then
  476.   begin
  477.     InitEnv;
  478.     CopyValue(util_env_find(Fenv, VariableName), Result);
  479.     Exit;
  480.   end else
  481.   begin
  482.     if CompareText('CONTENT_LENGTH', HeaderName) = 0 then
  483.       HeaderValue := pblock_findval('content-length', Frq.headers)
  484.     else if CompareText('CONTENT_TYPE', HeaderName) = 0 then
  485.       HeaderValue := pblock_findval('content-type', Frq.headers)
  486.     else if CompareText('PATH_INFO', HeaderName) = 0 then
  487.       HeaderValue := pblock_findval('path-info', Frq.vars)
  488.     else if CompareText('PATH_TRANSLATED', HeaderName) = 0 then
  489.       HeaderValue := pblock_findval('path-translated', Frq.vars)
  490.     else if CompareText('QUERY_STRING', HeaderName) = 0 then
  491.       HeaderValue := pblock_findval('query', Frq.reqpb)
  492.     else if CompareText('REMOTE_ADDR', HeaderName) = 0 then
  493.       HeaderValue := pblock_findval('ip', Fsn.client)
  494.     else if CompareText('REMOTE_HOST', HeaderName) = 0 then
  495.       HeaderValue := session_dns(Fsn)
  496.     else if CompareText('REQUEST_METHOD', HeaderName) = 0 then
  497.       HeaderValue := pblock_findval('method', Frq.reqpb)
  498.     else if CompareText('SCRIPT_NAME', HeaderName) = 0 then
  499.       HeaderValue := pblock_findval('uri', Frq.reqpb)
  500.     else if CompareText('SERVER_NAME', HeaderName) = 0 then
  501.       HeaderValue := system_version
  502.     else if CompareText('ALL_HTTP', HeaderName) = 0 then
  503.     begin
  504.       CopyValue(PChar(AllHeaders), Result);
  505.       Exit;
  506.     end else if CompareText('SERVER_PORT', HeaderName) = 0 then
  507.     begin
  508.       CopyValue(PChar(IntToStr(conf_getglobals.Vport)), Result);
  509.       Exit
  510.     end else if CompareText('SERVER_PROTOCOL', HeaderName) = 0 then
  511.       HeaderValue := pblock_findval('protocol', Frq.reqpb)
  512.     else if CompareText('URL', HeaderName) = 0 then
  513.       HeaderValue := pblock_findval('uri', Frq.reqpb)
  514.     else if CompareText('OBJECT_CONFIG', HeaderName) = 0 then
  515.     begin
  516.       CopyValue(PChar(Format('<pre>%s</pre><br>', [GetObjectConfig(Frq.os)])), Result);
  517.       Exit;
  518.     end else
  519.     begin
  520.       Result := False;
  521.       SetLastError(ERROR_INVALID_INDEX);
  522.     end;
  523.   end;
  524.   try
  525.     CopyValue(HeaderValue, Result);
  526.   finally
  527.     system_free(HeaderValue);
  528.   end;
  529. end;
  530.  
  531. function TISAPISession.WriteClient(Buffer: Pointer; var Bytes: DWORD): Boolean;
  532. var
  533.   nWritten: DWORD;
  534. begin
  535.   LogMessage('WriteClient($%p, %d)'#13#10, [Buffer, Bytes]);
  536.   nWritten := net_write(Fsn.csd, Buffer, Bytes);
  537.   Result := not (nWritten < Bytes) and not (nWritten = DWORD(IO_ERROR));
  538.   Bytes := nWritten;
  539. end;
  540.  
  541. function TISAPISession.ReadClient(Buffer: Pointer; var Size: DWORD): Boolean;
  542. var
  543.   nBuf, nRemaining: DWORD;
  544. begin
  545.   LogMessage('ReadClient($%p, %d)'#13#10, [Buffer, Size]);
  546.   nRemaining := Size;
  547.   while nRemaining > 0 do
  548.   begin
  549.     with Fsn.inbuf^ do
  550.       if pos < cursize then
  551.       begin
  552.         nBuf := cursize - pos;
  553.         if nBuf > Size then nBuf := Size;
  554.         Move(inbuf[pos], Buffer^, nBuf);
  555.         Inc(pos, nBuf);
  556.         Dec(nRemaining, nBuf);
  557.         Inc(Integer(Buffer), nBuf);
  558.       end else
  559.       begin
  560.         nBuf := net_read(Fsn.csd, Buffer, nRemaining, NET_READ_TIMEOUT);
  561.         if nBuf = DWORD(IO_ERROR) then Break;
  562.         Inc(pos, nBuf);
  563.         Dec(nRemaining, nBuf);
  564.       end;
  565.   end;
  566.   if nRemaining = 0 then
  567.     Result := True
  568.   else Result := False;
  569.   Size := Size - nRemaining;
  570. end;
  571.  
  572. function TISAPISession.ServerSupportFunction(HSERequest: DWORD; Buffer: Pointer;
  573.   Size: LPDWORD; DataType: LPDWORD): Boolean;
  574. var
  575.   Content: PChar;
  576.   ContentLen: Integer;
  577.   ContentStr: string;
  578.  
  579.   // This function will parse out any ISAPI application supplied headers and
  580.   // place them into the appropriate parameter block.
  581.   function SkipHeaders(Content: PChar): PChar;
  582.   var
  583.     T: array[0..REQ_MAX_LINE - 1] of Char;
  584.     pb: PPblock;
  585.     NetBuf: TNetBuf;
  586.   begin
  587.     if Content <> nil then
  588.     begin
  589.       pb := pblock_create(10);
  590.       try
  591.         FillChar(NetBuf, SizeOf(NetBuf), 0);
  592.         with NetBuf do
  593.         begin
  594.           cursize := StrLen(Content);
  595.           maxSize := curSize;
  596.           inbuf := Content;
  597.         end;
  598.         http_scan_headers(nil, @NetBuf, T, pb);
  599.         pblock_copy(pb, Frq.srvhdrs);
  600.         // Skip past the headers if present
  601.         Inc(Content, NetBuf.pos);
  602.         Result := Content;
  603.       finally
  604.         pblock_free(pb);
  605.       end;
  606.     end else Result := Content;
  607.   end;
  608.  
  609.   procedure SetStatus(StatusStr: PChar);
  610.   var
  611.     StatusCode: Integer;
  612.     I: Integer;
  613.   begin
  614.     if StatusStr = nil then
  615.       StatusCode := PROTOCOL_OK
  616.     else
  617.     begin
  618.       StatusCode := StrToIntDef(Copy(StatusStr, 1, 3), PROTOCOL_OK);
  619.       for I := 0 to 3 do
  620.       begin
  621.         if StatusStr[0] = #0 then Break;
  622.         Inc(StatusStr);
  623.       end;
  624.     end;
  625.     http_status(Fsn, Frq, StatusCode, StatusStr);
  626.   end;
  627.  
  628. begin
  629.   case HSERequest of
  630.     HSE_REQ_SEND_RESPONSE_HEADER:
  631.       begin
  632.         if DataType <> nil then
  633.           Content := PChar(Datatype)
  634.         else Content := #0;
  635.         if Size <> nil then
  636.           LogMessage('ServerSupportFunction(HSE_REQ_SEND_RESPONSE_HEADER' +
  637.             ', $%p, %d, %s)'#13#10, [Buffer, Size^, Content])
  638.         else LogMessage('ServerSupportFunction(HSE_REQ_SEND_RESPONSE_HEADER' +
  639.             ', $%p, nil, %s)'#13#10, [Buffer, Content]);
  640.         SetStatus(PChar(Buffer));
  641.         param_free(pblock_remove('content-type', Frq.srvhdrs));
  642.         param_free(pblock_remove('content-length', Frq.srvhdrs));
  643.         Content := SkipHeaders(PChar(DataType));
  644.         ContentLen := StrLen(Content);
  645.         Result := True;
  646.         if http_start_response(Fsn, Frq) <> REQ_NOACTION then
  647.         begin
  648.           if (Content <> nil) and (Content[0] <> #0) then
  649.             if net_write(Fsn.csd, Content, ContentLen) < ContentLen then
  650.               Result := False;
  651.         end else Result := False;
  652.       end;
  653.     HSE_REQ_SEND_URL_REDIRECT_RESP:
  654.       begin
  655.         if Size <> nil then
  656.           LogMessage('ServerSupportFunction(HSE_REQ_SEND_URL_REDIRECT_RESP' +
  657.             ', %s, %d)'#13#10, [PChar(Buffer), Size^])
  658.         else LogMessage('ServerSupportFunction(HSE_REQ_SEND_URL_REDIRECT_RESP' +
  659.             ', %s, nil)'#13#10, [PChar(Buffer)]);
  660.         http_status(Fsn, Frq, PROTOCOL_REDIRECT, 'Object moved');
  661.         param_free(pblock_remove('content-type', Frq.srvhdrs));
  662.         param_free(pblock_remove('content-length', Frq.srvhdrs));
  663.         if Buffer <> nil then
  664.         begin
  665.           pblock_nvinsert('Location', PChar(Buffer), Frq.srvhdrs);
  666.           ContentStr := Format(DocumentMoved, [PChar(Buffer)]);
  667.           ContentLen := Length(ContentStr);
  668.           pblock_nvinsert('content-type', 'text/html', Frq.srvhdrs);
  669.           pblock_nninsert('content-length', ContentLen, Frq.srvhdrs);
  670.           Result := True;
  671.           if http_start_response(Fsn, Frq) <> REQ_NOACTION then
  672.           begin
  673.             if net_write(Fsn.csd, PChar(ContentStr), ContentLen) < ContentLen then
  674.               Result := False;
  675.           end else Result := False;
  676.         end else raise EISAPIException.CreateRes(@sInvalidRedirectParam);
  677.       end;
  678.     HSE_REQ_SEND_URL:
  679.       begin
  680.         Result := False;
  681.       end;
  682.     HSE_REQ_MAP_URL_TO_PATH:
  683.       begin
  684.         Result := True;
  685.         Content := request_translate_uri(Buffer, Fsn);
  686.         if Content <> nil then
  687.         try
  688.           StrPLCopy(Buffer, Content, Size^);
  689.           if Size^ < StrLen(Content) + 1 then
  690.           begin
  691.             Result := False;
  692.             SetLastError(ERROR_INSUFFICIENT_BUFFER);
  693.           end;
  694.         finally
  695.           system_free(Content);
  696.         end else
  697.         begin
  698.           Result := False;
  699.           SetLastError(ERROR_NO_DATA);
  700.         end;
  701.       end;
  702.     HSE_REQ_DONE_WITH_SESSION:
  703.       begin
  704.         FEvent.SetEvent;
  705.         Result := True;
  706.       end;
  707.   else
  708.     Result := False;
  709.   end;
  710. end;
  711.  
  712. procedure TISAPISession.ProcessExtension;
  713. begin
  714.   LogMessage('ProcessExtension -- Application: %s'#13#10, [FISAPIApplication.FFileName]);
  715.   if Assigned(FISAPIApplication.HTTPExtensionProc) then
  716.     case FISAPIApplication.HTTPExtensionProc(FECB) of
  717.       HSE_STATUS_ERROR: raise EISAPIException.CreateRes(@sISAPIAppError);
  718.       HSE_STATUS_PENDING: FEvent.WaitFor(INFINITE);
  719.     end;
  720. end;
  721.  
  722. { TISAPIApplicationList }
  723.  
  724. constructor TISAPIApplicationList.Create;
  725. begin
  726.   FList := TList.Create;
  727.   FCriticalSection := TCriticalSection.Create;
  728.   FLogfd := SYS_ERROR_FD;
  729. end;
  730.  
  731. destructor TISAPIApplicationList.Destroy;
  732. begin
  733.   ClearApplications;
  734.   FList.Free;
  735.   FCriticalSection.Free;
  736.   if FLogfd <> SYS_ERROR_FD then
  737.     system_fclose(FLogfd);
  738.   inherited Destroy;
  739. end;
  740.  
  741. procedure TISAPIApplicationList.AddApplication(ISAPIApplication: TISAPIApplication);
  742. begin
  743.   FCriticalSection.Enter;
  744.   try
  745.     if FList.IndexOf(ISAPIApplication) = -1 then
  746.       FList.Add(ISAPIApplication);
  747.   finally
  748.     FCriticalSection.Leave;
  749.   end;
  750. end;
  751.  
  752. procedure TISAPIApplicationList.ClearApplications;
  753. var
  754.   ISAPIApplication: TISAPIApplication;
  755. begin
  756.   FCriticalSection.Enter;
  757.   try
  758.     while FList.Count > 0 do
  759.     begin
  760.       ISAPIApplication := FList.Last;
  761.       FList.Remove(ISAPIApplication);
  762.       ISAPIApplication.Free;
  763.     end;
  764.   finally
  765.     FCriticalSection.Leave;
  766.   end;
  767. end;
  768.  
  769. function TISAPIApplicationList.FindApplication(const AFileName: string): TISAPIApplication;
  770. var
  771.   I: Integer;
  772. begin
  773.   FCriticalSection.Enter;
  774.   try
  775.     for I := 0 to FList.Count - 1 do
  776.     begin
  777.       Result := FList[I];
  778.       with Result do
  779.         if CompareText(AFileName, FFileName) = 0 then
  780.           Exit;
  781.     end;
  782.     Result := nil;
  783.   finally
  784.     FCriticalSection.Leave;
  785.   end;
  786. end;
  787.  
  788. function TISAPIApplicationList.InitLog(pb: PPblock; sn: PSession; rq: Prequest): Integer;
  789. var
  790.   fn: Pchar;
  791. begin
  792.   fn := pblock_findval('file', pb);
  793.   try
  794.  
  795.     if fn = nil then
  796.     begin
  797.       pblock_nvinsert('error', 'TISAPIApplicationList: please supply a file name', pb);
  798.       Result := REQ_ABORTED;
  799.       Exit;
  800.     end;
  801.  
  802.     FLogfd := system_fopenWA(fn);
  803.     if FLogfd = SYS_ERROR_FD then
  804.     begin
  805.       pblock_nvinsert('error', 'TISAPIApplicationList: please supply a file name', pb);
  806.       Result := REQ_ABORTED;
  807.       Exit;
  808.     end;
  809.   finally
  810.     system_free(fn);
  811.   end;
  812.   {* Close log file when server is restarted *}
  813.   Result := REQ_PROCEED;
  814. end;
  815.  
  816. function TISAPIApplicationList.LoadApplication(const AFileName: string): TISAPIApplication;
  817. begin
  818.   Result := FindApplication(AFileName);
  819.   if Result = nil then
  820.     Result := TISAPIApplication.Create(Self, AFileName);
  821. end;
  822.  
  823. procedure TISAPIApplicationList.LogMessage(const Fmt: string; Params: array of const);
  824. var
  825.   logmsg: string;
  826.   len: Integer;
  827. begin
  828.   if FLogfd <> SYS_ERROR_FD then
  829.   begin
  830.     FmtStr(logmsg, Fmt, Params);
  831.     len := Length(logmsg);
  832.     system_fwrite_atomic(FLogfd, PChar(logmsg), len);
  833.   end;
  834. end;
  835.  
  836. procedure TISAPIApplicationList.RemoveApplication(ISAPIApplication: TISAPIApplication);
  837. begin
  838.   FCriticalSection.Enter;
  839.   try
  840.     if FList.IndexOf(ISAPIApplication) > -1 then
  841.       FList.Remove(ISAPIApplication);
  842.   finally
  843.     FCriticalSection.Leave;
  844.   end;
  845. end;
  846.  
  847. procedure InitISAPIApplicationList;
  848. begin
  849.   if ISAPIApplicationList = nil then
  850.     ISAPIApplicationList := TISAPIApplicationList.Create;
  851. end;
  852.  
  853. procedure DoneISAPIAPplicationList;
  854. begin
  855.   ISAPIApplicationList.Free;
  856.   ISAPIApplicationList := nil;
  857. end;
  858.  
  859. end.
  860.