OmniHTTPd is an ISAPI compliant Web server. It is very easy to install and configure, and
Web apps made with Delphi are very easily debugged with it.
You can find OmniHTTPd here.
At least since version 5 of Delphi, there have been some features of Delphi WebBroker
apps that haven't worked well with OmniHTTPd, due to the fact that OmniHTTPd doesn't implement
ISAPI exactly as IIS does.
This article focuses on one such feature, and also focuses on Delphi 6 features that
require changes for WebBroker apps (including Web services) to work with OmniHTTPd.
TWebRequest.Host property
If you build a WebBroker app with Delphi 5 or greater (possibly Delphi 4 also; I
haven't checked), using the Host property of TWebRequest does not work under
OmniHTTPd.
Let's see why by examining how the Host property is accessed.
From TWebRequest in HTTPApp.PAS:
property Host: string index 10 read GetStringVariable;
Host is an "indexed" property, which means that the index value of 10 is passed to the
GetStringVariable method. Examining the GetStringVariable method of TISAPIRequest in
ISAPIHTTP.PAS:
function TISAPIRequest.GetStringVariable(Index: Integer): string;
begin
case Index of
0: Result := ECB.lpszMethod;
3: Result := ECB.lpszQueryString;
4: Result := ECB.lpszPathInfo;
5: Result := ECB.lpszPathTranslated;
1..2, 6..24, 26..28: Result := GetFieldByName(ServerVariables[Index]);
25: if ECB.cbAvailable > 0 then
SetString(Result, PChar(ECB.lpbData), ECB.cbAvailable);
else
Result := '';
end;
end;
This code shows that GetFieldByName is called, passing the value of the ServerVariables
array with an index of 10, which is HTTP_HOST. GetFieldByName calls the GetServerVariable
method of the ECB (Extension Control Block) structure, which is supplied by the ISAPI
server.
In the case of OmniHTTPd, for some reason or another, the ECB does not return the
HTTP_HOST variable. Fortunately, an alternative is to use the ALL_HTTP value, which
lists HTTP_HOST within it.
Fixing the TWebRequest.Host property for OmniHTTPd
To fix this problem, I made a number of changes to ISAPIHTTP.PAS:
type
TISAPIRequest = class(TWebRequest)
private
FECB: PEXTENSION_CONTROL_BLOCK;
// Fix for OmniHTTPd - DPN SEP 2001
function GetHostName: string;
function GetAllHTTPValue(const VarName: string): string;
...
function TISAPIRequest.GetStringVariable(Index: Integer): string;
begin
case Index of
0: Result := ECB.lpszMethod;
3: Result := ECB.lpszQueryString;
4: Result := ECB.lpszPathInfo;
5: Result := ECB.lpszPathTranslated;
// Fix for OmniHTTPd - DPN SEP 2001
// 1..2, 6..24, 26..28: Result := GetFieldByName(ServerVariables[Index]);
1..2, 6..9, 11..24, 26..28: Result := GetFieldByName(ServerVariables[Index]);
10: Result := GetHostName;
25: if ECB.cbAvailable > 0 then
SetString(Result, PChar(ECB.lpbData), ECB.cbAvailable);
else
Result := '';
end;
end;
// Fix for OmniHTTPd - DPN SEP 2001
function TISAPIRequest.GetHostName: string;
begin
Result := GetFieldByName(ServerVariables[10]);
if Result = '' then
Result := GetAllHTTPValue(ServerVariables[10]);
end;
function TISAPIRequest.GetAllHTTPValue(const VarName: string): string;
var
Str: TStrings;
i: integer;
begin
Result := '';
Str := TStringList.Create;
try
Str.Text := GetFieldByName('ALL_HTTP');
for i := 0 to Str.Count - 1 do
if Pos(VarName, Str[i]) > 0 then
begin
Result := Trim(Copy(Str[i], Pos(':', Str[i]) + 1, Length(Str[i])));
break;
end;
finally
Str.Free;
end;
end;
// End fix
Note that I created a new method, GetHostName, so that any future changes to
the way in which the host name is retrieved are localized to that method.
The necessity for this change becomes obvious when you create Web services with
Delphi 6 and run them under OmniHTTPd.
The above outlines changes to fix the Host property for ISAPI apps only. The
changes required for CGI apps are almost identical. These are left as an exercise
for the reader!
Delphi 6 Web services
When the WSDL for Web services in a SOAP server is published, the WSDLPublish
component uses the Host property of TWebRequest to publish links to the WSDL for
each Web service. Without the fix as outlined above, the Host value is empty,
thus creating an invalid link.
With the fix applied, you can successfully navigate the WSDL in your SOAP
server.
ISAPI Thread Pooling
Delphi 6 introduces a new unit to support the ISAPI thread pooling features of
IIS. As this feature is for IIS only, the unit needs to be removed from the
project's uses clause when using Web servers other than IIS, including OmniHTTPd:
library Project1;
uses
WebBroker,
ISAPIThreadPool, // <----- Remove this unit
ISAPIApp,
Unit1 in 'Unit1.pas' {WebModule1: TWebModule};
Remember to return the unit to your code if you decide to deploy on IIS.
Dave Nottage is CTO of Pure Software Technology, a software development company
specializing in Delphi. He can be reached at dave@b3.com.au
and the company's Web site is http://www.puresoftwaretech.com.