Rick Strahl's Weblog
Rick Strahl's FoxPro and Web Connection Weblog
White Papers | Products | Message Board | News |

Apache 2.2 Support in Web Connection


June 08, 2007 •

About a year back when Apache shipped version 2.2 of the Apache Web Server, the Apache Foundation basically broke compatibility with Web Connection as they basically tossed out the old module format and required recompilation (and a number of changes) to existing modules in order to run under Apache 2.2.

 

Web Connection interfaces to Apache through a slightly modified version of mod_isapi which is a standard Apache module that ships with the stock server. Mod_isapi gives basic ISAPI compatibility to Apache and allows it to run ISAPI components like the Web Connection ISAPI DLL. The raw module however has a few small issues that differ slightly in the way IIS handles ISAPI calls, mainly in the way some of the server variables are reported. The most serious of these has to do with reporting of the physical path which is inconsistent in the Apache implementation. The other is lack of support of passing through the HTTP_AUTHORIZATION header which pretty much breaks all of Web Connection’s default internal security mechanisms either using Windows Authentication or Basic Authentication.

 

Actually Apache 2.2’s ISAPI implementation mostly fixes the path fixup issues – in fact after reviewing the source code for mod_isapi some of my bug reports from 5 years back seem to have made it into the build (among other things the ability to write a raw response including headers using WriteClient which wasn’t previously possible).

 

In any case the good news is that I’ve updated the Web Connection Apache module and re-merged the  fixes and updates so Web Connection will now work with the latest version of Apache (2.2.x) as well as 2.0

Non File backed Requests

In the past there’s been one big shortcoming when using Apache: The inability to easily execute ‘file-less’ pages. Due to the way Apache maps requests it requires a backing file for a dynamic URL hit. Web Connection pages of course – especially pre-5.x pages – often use only methods without any backing files which caused a problem. The workaround had been to copy an empty file to disk for each request.

 

Apache does support something called a ScriptAlias which allows mapping a specific path to a binary handler. The process is a bit obscure as it maps a logical path to a physical executable (WTF?) and in previous versions of Apache I’ve never been able to get this to work although others apparent had as previously mentioned. I suspect the problem wasn’t actually Apache per se, but the way that requests were mapped into the ISAPI module – the ISAPI module never saw the redirected requests.

 

With Apache 2.2 I gave this another shot and it does work just fine! This is great news as this will make Apache a lot more user friendly because it’ll be much closer match to IIS functionality.

 

While I was at it I also streamlined the configuration process which should now become a lot more straight forward as well and work much better with cumulative script map updates to a virtual directory.

 

For reference here’s a complete Apache configuration for a virtual directory (the LoadModule  and ScriptAlias settings are global settings) as you’d want to use it with Web Connection:

 

#*** WEB CONNECTION MODULE CONFIGURATION

LoadModule webconnection_isapi_module modules/mod_webconnection_isapi.so

#*** END WEB CONNECTION MODULE CONFIGURATION

 

 

#*** WEB CONNECTION VIRTUAL - apachedemo

 

Alias /apachedemo/ "C:/Program Files/Apache2.2/htdocs/ApacheDemo/"

#ISAPICacheFile "C:/Program Files/Apache2.2/htdocs/ApacheDemo/bin/wc.dll"

 

<directory "C:/Program Files/Apache2.2/htdocs/ApacheDemo/">

DirectoryIndex default.htm

Options ExecCGI

# AddHandler isapi-handler dll

AddHandler webconnection-isapi-handler dll

 

#*** WEB CONNECTION VIRTUAL SCRIPT MAPS

AddType application/webconnection-scriptmap .wcs .wcsx .wc .wwsoap .ap

Action application/webconnection-scriptmap "/apachedemo/bin/wc.dll"

#*** END WEB CONNECTION VIRTUAL SCRIPT MAPS

</directory>

 

#*** WEB CONNECTION SCRIPT ALIAS

ScriptAliasMatch (?i)^/apachedemo/.*.(wcs|wcsx|wc|wwsoap|ap)$ "C:\Program Files\Apache2.2\htdocs\ApacheDemo\bin\wc.dll"

#*** END WEB CONNECTION SCRIPT ALIAS

 

#*** END WEB CONNECTION VIRTUAL - apachedemo

 

Note that ScriptAliasMatch works with regular expressions, so you can use any RegEx expression that makes sense. The above basically matches any expressions anywhere on the server with the extensions that are supported. The regular expression by default is case sensitive but using the (?i) at the beginning sets case insensitive mode. It says:

Find any scripts that end in .wcsx,.wc,.wwsoap,.wcs,.ap in the apachedemo virtual directory and route them to the Web Connection Dll. Note that this can also be used to route things like jpgs or css or html files although this is probably not the best of ideas.

Problems with this Routing

Using ScriptAliasMatch is great because it routes any script extension to Web Connection, but unfortunately when this happens Apache mangles some of the paths. Normally when you access a page that actually has a backing file on disk a Web Server returns a PHYSICAL_PATH or PATH_TRANSLATED that points to the physical location of the file. On a script alias redirect however the Physical path and Path info both lose the original physical path. You get LOGICAL_PATH which points at say /apachedemo/testpage_noexist.ap whereas the physical path will point at c:\program files\apache2.2\htdocs\apachedemo\bin\wc.dll. If you want to do anything useful with the underlying script file your SOL.

 

I couldn’t find any way in Apache’s API to map a path from a logical path to a physical path (ie. like Server.MapPath in IIS) unfortunately in the module. It may be there but after digging for a half hour I gave up.

 

So my workaround here is to make a few assumptions when the code hits Web Connection. I compare the physical path and the logical path and if they don’t both point at the same base file then the code takes a stab at guessing at the root virtual path:

 

************************************************************************

* wwApacheRequest :: GetPhysicalPath

****************************************

***  Function: Works around some Apache Issues in how

***            the physical path is returned. This bug

***            affects a number of the various path related

***            Server variables from apache

************************************************************************

FUNCTION GetPhysicalPath()

LOCAL lcPathInfo, lcLogical, lnAt, lcAppPath

 

IF EMPTY(THIS.cPhysicalPath)  

      lcPathInfo = THIS.ServerVariables("PATH_TRANSLATED")

      IF EMPTY(lcPathInfo)

            lcPathInfo = THIS.ServerVariables("PHYSICAL_PATH")

   ENDIF  

   this.cPhysicalPath = STRTRAN( STRTRAN(lcPathInfo,"/","\"),"\\","\")

 

   IF UPPER(JUSTEXT(this.cPhysicalPath)) = "DLL"

         *** We have a ScriptAlias forwarding directive - the physical path is teh DLL

         *** and not the actual script file so let's try and fix it up

       lcLogical = this.GetLogicalPath()

       IF UPPER(JUSTEXT(lcLogical)) # "DLL"

               lnAt = ATC("\bin\",this.cPhysicalPath)

               IF lnAt > 0

                  lcAppPath = SUBSTR(this.cPhysicalPath,1,lnAt -1)

               ELSE

                  lcAppPath = JUSTPATH(this.cPhysicalPath)

               ENDIF

 

               this.cPhysicalPath = STRTRAN(lcAppPath + lcLogical,"/","\")

         ENDIF

   ENDIF

ENDIF

 

RETURN THIS.cPhysicalPath  

ENDFUNC

*  wwApacheRequest :: GetPhysicalPath

 

Basically the assumption is that if wc.dll either lives in the root of the site or in a BIN directory. If it’s bin the bin dir is stripped off. Otherwise the wc.dll’s path is used directly.

 

Web Connection actually has access to the ‘virtual path’ and it’s mapped physical path in Process.oConfig.cHtmlPagePath, but unfortunately the physical path is needed much earlier in the processing before a process routing has been established. So the above code has to make some assumptions and do its best to guess.

 

In most scenarios this won’t be a problem and if it is you can always customize the above method by subclassing and specifying this RequestClass instead.

 

While not optimal (I hate making assumptions <s>) this certainly will address most scenarios and give Web Connection much better cross server support with Apache than previously. I’m fairly excited with how this turned out especially since I was preparing for the worst when looking at converting the Apache module and finding only a few minor changes were required.

 

These changes will be in the next rev of Web Connection 5.0...

Posted in:

Feedback for this Weblog Entry