Tue, 04 Jan 2005  15:47

last updated Tue, 05 Feb 2008  16:10


Ionic's Isapi Rewrite Filter (IIRF)  1.2.14 final R2

The mod_rewrite for Apache is widely used to rewrite URL
requests before they reach web application engines.  IIS 5.0
(Windows 2000) 5.1 (Windows XP) and v6.0 (Windows 2003) lack a
built-in URL rewriting function.

There are several add-on tools that can add the URL re-writing
function to IIS. All are implemented as ISAPI Filters. 
  - ASP.NET provides some URL mapping capability
  - the IIS v6.0 Resource Kit includes the UrlRemap tool.
  - IISRewrite - ??
  - ISAPI_Rewrite - 
    includes a "lite" version available for free. 
  - Mod_Rewrite 2

All of them have drawbacks. 
The ASP.NET support requires that all URLs map through ASP.NET;
even static files would have to be served by the ASP.NET
runtime.  This can imply a large performance cost.  

The IIS6 Resource Kit filter is provided by Microsoft, and is
supported.  The drawback: it does not allow specifying rules via
Regular expressions, and as a result it is not as flexible as
some would like.

The ISAPI_Rewrite module is commercially supported, and does
use Regular Expressions, but is expensive. Likewise Mod_Rewrite and
IISRewrite.  There is a "Lite" version of ISAPI_Rewrite, but it
does not do Regular Expressions. Doh! 

IIRF adds one more option to the list. IIRF is an open-source
Rewrite filter, available in source or binary form at no
cost. It does Regular-Expression mapping based on the open
source PCRE library [PCRE = Perl-compatible regular
expressions].  The source code for the filter is available so
you can analyze or modify the filter if you want to, or need
to. As well, the source for the PCRE library is also available,
from its owners.

If you're going to use IIRF, I suggest you read everything that
follows in this readme file. 



Why Rewrite URLs? 
---------------------------------
There are lots of reasons to rewrite URLs:
Search Engine Optimization (SEO) is one.  

Making user-friendly URLs is another. 

Faking people out is another.  The url can say .jsp but maybe
the implementation is .php.  This is also useful when migrating
from one technology to another in stages.  You can keep the URLs
the same even after you've migrated from JSP to PHP. 

Injecting custom processing without breaking existing URLs is
another. (For example, insert special image handling logic
behind a .jpg URL).  

Filtering URL requests. 

You can imagine lots of other reasons, too. 

IIRF lets you do any of these things.



Implementation
---------------------------------

This filter is implemented in C. Starting with version 1.2.5,
IIRF is compiled with the Microsoft VC8 compiler, shipped with
Visual Studio 2005, or with Visual C++ 2005 Express Edition.

Previous versions were compiled with the Microsoft VC7 compiler
that shipped with Visual Studio 2003.




Recent Changes
---------------------------------
1. Conditional rewrite rules (RewriteCond). Like the Apache module. 
   As of v1.2.10, multiple RewriteCond directives can be chained
   together via logical AND or logical OR.

2. Automatic reload of settings when the ini file is
   changed, without restarting IIS.

3. Logfile names are dependent upon the process ID. 

4. Browser-based Redirection (HTTP 302 or 301 etc) to local or remote hosts

5. Not Found (404) and Forbidden (403) return codes are now supported.

6. [U] and [I] modifier flags supported for storing original URL
   in a server variable, and for case-insensitive pattern
   matching, respectively. 

7. -d and -f flags for modifying filter behavior based on file
    or directory existence.

8. RewriteFilterPriority directive. 



See the ReleaseNotes.txt file for more details. 



Installation 
---------------------------------

Installation is simple, but manual.  You need to install the
ISAPI Filter, as with any ISAPI.  Do it through the IIS MMC
panel.  Add the filter to the all web sites, or to a
particular website.  


Follow these steps

1. Copy the filter DLL to an appropriate folder, such as 
c:\windows\system32\inetsrv .   Or it could be in c:\wwwroot
somewhere.  Or it could be in a totally separate directory tree,
with permissions granted to the appropriate Windows principal
(IUSR_hostname).  It's up to you.   The only thing - don't put
it in the web document tree.  (it causes problems with detecting
changes in the ini file.  there's more about this later in the
readme).  

2. Open the Internet Service Manager (MMC). 
You can do this via Start...Run...%SystemRoot%\System32\inetsrv\iis.msc
or you can browse on WinXP to Start...Control
Panel...Administrative Tools....Internet Information Services.


3. Select the appropriate level for the ISAPI filter: 

 - to use the ISAPI filter with all Web sites, select the "Web Sites"  
   icon just under the machine name. 
 - to use the ISAPI filter with a specific Web site, select the icon 
   for that Web site (for example, the default Web site). 
 
4. Right-click the level (icon) that you selected. Click the
   Properties button.

5. Click the ISAPI Filters tab.

6. Click Add. 

7. Type a name for the ISAPI filter. Eg, "Ionic Rewriter". 

8. Click Browse and select the ISAPI filter DLL that you copied in
   step 1. 

9. Click OK. 

10. Stop the IISADMIN service. To do this, either type net stop
    iisadmin /y at a command prompt, or use the Services applet that
    is located in Administrative Tools 

11. Start the World Wide Web Publishing Service.  Do this by typing
    net start w3svc at a command prompt, or by using the Services
    applet that is located in Administrative Tools.


For detailed instructions from Microsoft on
how to do add ISAPI filters, see here:
http://support.microsoft.com/kb/150312/EN-US/


You can place the IsapiRewrite4.dll file anywhere it will be
accessible to IIS.  In Windows XP Pro, this might be
c:\windows\system32\inetsrv .   Or it could be in c:\wwwroot
somewhere.  Or it could be in a totally separate directory tree,
with permissions granted to the appropriate Windows principal
(IUSR_hostname).  It's up to you.   The filter will look for its
settings in a file called IsapiRewrite4.ini, placed in the same
directory as the DLL file.

On Windows Server 2003, the same thing applies.  If you have
multiple web sites on WS2003, and want multiple installations of
IIRF, then install the DLL and .ini file in separate places, and
configure the ISAPI filter separately for each website.  The ini
files may be different for each installation.  

On WS2003, you must add IIRF to the allowed Web Service
Extensions, for each web that uses IIRF. Each instance of Ionics
needs to be added to the list.

I have tested IIRF on Windows Vista with IIS7; it works fine.  I
have not tested it on Windows Server "Longhorn" with IIS7.

If you want to use the IirfVersion utility, you should copy
IirfVersion.exe into the same directory as you copied the
IsapiRewrite4.dll .   


Installation location and the IIS Metabase
--------------------------------------------
If you want to backup your metabase, do not install IIRF in
\windows\system32\intesrv.  As you know, you can install IIRF in
any directory you choose.  Installing IIRF in
\windows\system32\intesrv causes an inconvenience with IIS
administrative operations.  

In this case, any changes to the IIS configuration (adding a new
website, changing a virtual directory, turning on logging, etc.)
requires a service stop & start to ensure that the changes are
saved.  Also, if you try to back-up the IIS configuration
(right-clicking on the server, selecting Backup/Restore and then
creating a new backup), you will get an error that reads "The
process cannot access the file because it is being used by
another process."  In order to backup the IIS configuration in
this case, you need to stop IIS, and then perform the backup.
All of this can be inconvenient.


Why does this happen?  IIRF starts a thread that watches for
changes in a directory via the Win32 call
ReadDirectoryChangesW(). This essentially will keep open a file
in the directory. If the IIRF directory happens to be the same
directory as that which stores the IIS metabase, then you will
have this problem.

The solution is to install IIRF in a directory other than
inetsrv. Using a sub-folder is fine.






On Filter Settings
---------------------------------

All the settings for the filter are set in the .ini file.  The
location of this ini file is the same as the location of the
IsapiRewrite4.dll.  In other words, you should put the ini file 
in the same directory as where you put the dll.  

The ini file is automatically reloaded when it changes.  You do not
need to restart IIS in order to load in new settings.  They are
loaded dynamically. 

If you save an ini file with a bad format, IIRF will not load
the new settings, and will revert to the last good
configuration.  Take care to save valid ini files.  Check the
IIRF log to verify that the ini file you save, has actually been
successfully loaded.  

Also, try not to make many small changes in the ini file, saving
the file in each step. With each save of the file, IIRF will try
to reload the settings.  It is better to make all the changes
and save the file once.  



On Logging 
---------------------------------

Logging is relatively expensive.  Each log statement writes and
flushes the file.  For best performance, Turn logging down as
low as possible (to zero).  For general usage or monitoring of
URL re-writing, set LogLevel to 3.   For troubleshooting, set
LogLevel to 5. In between values are ok, too.

If you have a low-volume website, 10 hits per second or less,
you can probably safely keep logging on at level 3.  Mind the
disk space, though.  There is no auto-rollover of logfiles as
the file grows in size. You should add management of IIRF log
files to the list of tasks you periodically (and we hope
automatically) do on your web server, like archiving IIS logs,
etc.



Configuring the filter
---------------------------------

You specify settings for this ISAPI in an ini file.  The
location of the Ini file is in the same directory as the DLL,
with the same name, but with an extension of .ini.  By default
it is IsapiRewrite4.ini .

The format of the ini file is similar in philosophy to that of
the properties file used by Apache's mod_rewrite.  Because this
ISAPI is simpler in intent and execution than mod_rewrite, the
ini file is correspondingly simpler. 

These are the directives supported for the ini file: 

  IterationLimit
  MaxMatchCount  
  RewriteRule
  RewriteCond
  RewriteLog
  RewriteLogLevel
  RewriteFilterPriority

The directive names are NOT case-sensitive.  Whitespace
following the directive name is not significant.

A number of sample ini files are included in this
shipment. Check the tests and examples directories.


Below is an overview of the meaning of each of the directives: 


RewriteRule <url-pattern> <replacement-string>   [<modifiers>]
----------------------------------------------------------------

With this directive, administrators can specify how to map and
transform incoming URL requests.  This directive may occur more
than once in the file, and usually does.  There are 2 required
arguments for the directive: a regular expression pattern, and a
replacement string.  Within the replacement string you can
insert references to the matches from the pattern.  There is a
3rd "modifiers" argument, which is optional. We'll describe that
in a bit. These three arguments are separated by whitespace.

For example, the following rule will transform incoming URLs
that contain original into URLs that contain modified:

Example 1: 

  RewriteRule  ^/original/(.*).php  /modified/$1.aspx

With this rule, an incoming URL like this: 
   /original/subdir/page.php

will get mapped to this:
   /modified/subdir/page.aspx

The Regular Expression support is from PCRE.  It provides a
fully-powered, perl-compatible, regular expression library.  For
example, with IIRF, you can use rules to transform path elements
into query string params.

Example 2: 

   RewriteRule  ^/dinoch/album/([^/]+)/([^/]+).(jpg|JPG|PNG)   /chiesa/pics.aspx?d=$1&p=$2.$3


The above example says, for a URL request for an image, like 
   /dinoch/album/foo/bar.jpg

rewrite the URL to:
   /chiesa/pics.aspx?d=foo&p=bar.jpg

This rewritten URL would then be handled by the ASP.NET engine,
presumably the pics.aspx module, which could inject whatever
processing it needed to, before serving the bar.jpg image. For
example, thumbnailing the image, auditing the access count,
authorizing the request, or what have you. 

You could also do the converse, such as rewriting an ASPX request,
to a URL for a binary image file.  Such as:  

Example 3: 

   RewriteRule  ^/chiesa/pics.aspx?d=([^&]+)&p=(.+).(jpg|JPG|PNG)   /dinoch/album/$1/$2.$3

With this rule, an incoming request like 
   /chiesa/pics.aspx?d=foo&p=Alpha.jpg

would get rewritten to 
   /dinoch/album/foo/Alpha.jpg

and could then get served by the ISAPI for jpg files (typically
just directly served by IIS). I think**.  This is a performance
optimization, because with this rewrite rule, ASP.NET would
presumably not get involved with serving JPG files (unless the
.jpg extension were mapped to the ASP.NET ISAPI).  


[** because as of v1.2.10, IIRF uses SF_NOTIFY_AUTH_COMPLETE, it
may be "too late" to rewrite from an aspx to a static file like
a .jpg.  Not sure. Try it and let me know.  ]


The replacement string can contain:

- constant text

- references to the matched substrings in the input, in the form
  of $n, where n is a digit. (Eg $1, $2, $3...).  These are
  called back-references. 

- references to the matched substrings in the most recently
  evaluated RewriteCond associated to that RewriteRule.  [Don't
  worry too much about RewriteCond just yet.  We'll get to that
  in a minute. Just be aware that the replacement string can
  contain references to matched substrings from a RewriteCond.]
  These take the form %n, where n is a digit. (Eg %1, %2, %3...)

- references to server variables.  Eg, %{QUERY_STRING} in the
  replacement pattern embeds the query string of the incoming
  request, into the output (rewritten) URL. 

- case folding directives : #L #U #E #l #u
  These work just as \L \U \E \l \u do in PERL. 
  In other words, everything between #L and #E says "force
  lowercase".  Everything between #U and #E says "Force upper".
  and the #u and #l are one-character versions of those
  directives.




Example 4:

   RewriteRule ^/([^/]+)/([^/]+)/(\d+)/(\d+)/$  /index.php?option=com_$1&task=$2&id=$3&item=$4

This rule says, given a URL like this: 
   /content/blogcategory/0/33/
 
rewrite it to this:
 
   /index.php?option=com_content&task=blogcategory&id=0&item=33

This is especially useful for search engine optimization of
URLs, for Mambo, or is it Joomla?  (I am no expert on Mambo or
Joomla).



Example 5:

   RewriteRule ^(/[^.]+)$ /dispatch.fcgi?$1


This works with Ruby-on-Rails.  The pattern will match any URL
without a full-stop, rewriting it to be handled by
dispatch.fcgi. Should you not want to run FastCGI, you'll need
to change "dispatch.fcgi" to "dispatch.cgi", and create the
appropriate mapping within IIS.  

When mapping to dispatch.fcgi or .cgi, you may want to apply the
[L] modifier flag, which you will learn about in the next
section.

These are just a few examples.  As you can see, in the
RewriteRule pattern matching, you have a great deal of
flexibility.  In fact with IIRF, you have the full power of PCRE
regex support, including zero-width lookaheads, negation, match
counts, case-insensitivity, and so on.

See the provided Ini files, within the various test directories,
for more examples.



In IIRF V1.2.12 and prior, the replacement string cannot contain
spaces !  In v1.2.12, you can include spaces (and ampersands and
other characcters) by URL-escaping them.  For example, to
include a space in a replacement string, you would use %%20.  

Example 6: 

  RewriteRule  ^/downloads/myapp.exe /downloads/myapp%%201.2.exe 

The above rule would rewrite an incoming request for myapp.exe
to "myapp 1.2.exe"

For more on this, in the tests directory, see the
SpacesInReplacementString sub-directory. 



Including case-folding directives  in the replacement string,
tells the IIRF engine to change the case of the output URL.  The
#L...#E tells IIRF to fold case downward between the #L and the
#E.  The #U...#E sequence tells IIRF to fold case upward.  
The #l and #u directives tell IIRF to fold the case of the next
character only, either downward or upward. 

We do not use backslash, because in Windows, paths use
backslashes, and in some cases IIRF is dealing with paths. 

Example 7: 
  RewriteRule ^/lowercase/(.+)\.asp$  /lowercase-output/#L$1#E.asp  [L]
  RewriteRule ^/uppercase/(.+)\.asp$  /uppercase-output/#U$1#E.asp  [L]
  RewriteRule ^/OneCharLower/(.+)\.asp$  /OneCharLower-output/#l$1.asp  [L]
  RewriteRule ^/OneCharUpper/(.+)\.asp$  /OneCharUpper-output/#u$1.asp  [L]


The first rule above would rewrite an incoming request like
 /lowercase/This.Is.A.Test.asp  to /lowercase/this.is.a.test.asp

The second rule would do this: 
incoming:   /uppercase/TesTiNgCaseConVerSion.asp
output:  /uppercase/TESTINGCASECONVERSION.asp

And so on.



Modifiers
-------------------------------------------------

The optional modifier flags can tweak or change  the operation
of the  RewriteRule. The modifer flags supported in this release
of IIRF include:  
   R = Redirect
   NF = Not found
   L = Last test if match
   F = Forbidden
   I = Do case-insensitive matching
   U = Store original url in server Variable HTTP_X_REWRITE_URL

The flags must be specified in square brackets.  If you need to
combine flags together - for example to combine a redirect with
a case-insensitive match - separate the flags with a comma.
Example [R,I].  

It makes sense to combine the case-insensitive [I] flag, or the
keep-original-url [U] flag with some other flags, but most
combinations of flags do not make sense.  Often they are
mutually exclusive.  Example: [R,L] - implies a redirect and
also says "don't look for more matches."  But a Redirect, or a
Not Found, or a Forbidden, all imply that IIRF will stop doing
pattern matches immediately. 

So, at this time, such combinations of flags are not supported.
You won't get a runtime error if you do this, but you will get a
grumpy warning message in the log file, and the behavior of IIRF
in this case is not defined.

Also, if you use an unsupported flag character (example: [Q]),
IIRF will emit a warning message, and will ignore the flag.  So
do check your logs to verify that you've fashioned your rules
and modifiers properly.


Here's some further discussion on each flag. 

[R]  or [R=code] 
----------------
A RewriteRule with this modifier causes a browser redirection -
the ISAPI filter issues a "302 Redirect" back to the browser,
setting the Location header in that response to the URL
specified by the replacement string. When the 302 code is
returned to the browser, the browser then re-submits the request
to the new location.  In contrast to rewrite operations, with
browser redirects, the URL bar in the browser is updated.

The [R=code] form allows you to specify the HTTP status code.
The default code is 302 (HTTP Status code for Moved
Temporarily), but you may wish to use 301 (Moved Permanently),
or some other redirect code.  The range of valid values for the
R code is 301 to 399.  If you specify a code outside that range,
the default 302 code will be used. If you specify a code that is
not valid for HTTP, IIRF will blindly return that code to the
requesting browser.  So do be careful.

See the IETF RFC 2616 for complete details on HTTP Redirect
codes.  (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)


Example 8: 

   RewriteRule ^/(W.*)$  http://server.dyndns.org:7070/$1   [R]


Given this request:
   /Wookie
 
This rule would redirect the browser to this location:
 
   http://server.dyndns.org:7070/Wookie


With this directive, IIRF can redirect to a different IIS
instance on the same box, a different IIS on a different box, or
a non-IIS server on either the local or remote box.  For
example, if you have multiple websites on a single Windows
Server machine, an IIRF installed on one of those instances
would be able to redirect to another instance.

This directive can also be used to redirect requests to an
anchor point in an HTML document. (URLs containing a # name)

Prior to version 1.2.11c, the redirect logic did not handle
https: targets. with v1.2.11c and later, https is handled.


Example 9:

      RewriteRule ^/([^.?]+[^.?/])$ /$1/ [R=301]

This rule says, add a trailing slash to all URLs without file
extensions. 

The above rule will have the following results:

'/foo/something'       ==> Browser Redirect (301) to '/foo/something/' 
'/home/foo/admin'      ==> Redirect (301) to         '/home/foo/admin/' 
'/module.php'          ==> No rewrite  
'/foo/something.aspx'  ==> No rewrite  
'/foo/something.'      ==> No rewrite  

I could imagine combining this rule with a "directory existence"
RewriteCond (see the notes on the -d flag), so that the redirect
would occur only if the target directory actually exists.



[L] 
----
This flag tells IIRF to process no more patterns if the current
one matches.  The default behavior is to recurse, until no match
is found, or until the iteration limit is reached. 


[NF] 
----
When this pattern matches, the return code given is 404, Not
Found.  Useful to "turn off" certain URLs on the server
selectively, without actually removing the web content.  Also,
combined with a RewriteCond, the 404 can be used to filter
results for a given requester, when a given url pattern
matches.  You can imagine other uses as well. 

[F]
---
Similar to the NF flag, this one sets a 403, Forbidden return
code.  Like the [NF] flag, the [F] flag can be utilized with a
RewriteCond for flexibility - you could return a 403 only for
requests coming from a certain REMOTE_ADDR, or you could deny
requests that do not have HTTPS enabled.  And so on.

[I]
---
Do a case-insensitive match on the pattern.  When using this
modifier flag, a pattern like ^/(.*).php$ will match a url like
Home.PHP.  

PCRE, the regular expression engine used by IIRF, supports a
syntax within the regular expression itself, for turning on
case-insensitive matching within the pattern itself.  Place a
(?i) anywhere in the pattern, and all matching after that point
in the pattern is done without regard for case.  Turn off this
behavior with (?-i). In this way, some portions of the pattern
can be matched in a case insensitive manner, and others will
not.  In the specific case, use (?i) at the beginning of the
pattern and the entire pattern is matched in a case insensitive
manner.  Consult the PCRE documentation for complete details.
(See http://www.pcre.org/pcre.txt and search for INTERNAL OPTION
SETTING). 

Because of the support of (?i) in PCRE, the [I] flag is
redundant and not really unnecessary, but it is included in IIRF
because it may be familiar for some who are accustomed to
Isapi_Rewrite, and it may be more readable as well.  

Consult the tests\CaseInsensitive directory for examples of
case-insensitive matching. 


[U]
---
This flag tells the filter to store the original, unmodified URL
in the server variable called HTTP_X_REWRITE_URL, and also tells
IIS to log the original, pre-rewrite URL in the IIS log file.
This is useful if you want to have generic handler logic (in
say, CFMX) that can do its own parsing of the original URL, or
if you want to expose Search-Engine Friendly URLs, and want to
preserve those URLs in the IIS log files for click analysis.

Unmangling will occur when ANY rule decorated with the [U] flag
is satisfied for a given incoming URL.  Remember, IIRF recurses
on URLs.  It may rewrite an incoming URL, then rewrite the result
of the rewrite.  It continues until the iteration limit is
reached, or until no more rules are satisfied.  If any of the
rules applied to a given URL include [U], then unmangling occurs.

One noteworthy behavior associated to use of the [U] flag on
Windows Server 2003, with the kernel-mode IIS cache enabled: To
implement this, IIRF uses the SF_NOTIFY_LOG event for IIS.
Registering for this event is considered "cache unfriendly", and
actually turns off the kernel response cache on IIS6.  This can
mean a performance degradation on IIS6 when your site relies on
the kernel-mode cache.

Because of this, IIRF asks to receive log events only when the
rules in the ini file say that it needs log events. In other
words, only when the [U] flag is employed in at  one or more
RewriteRules.  

But, the filter registers for notifications only once, at filter
startup, and so because of this, changes to the un-mangling
settings on rules work differently than changes to any other
filter settings in the ini file.  In short, changes involving the
use of [U] flags are not always immediately effective, and in
some cases you will need to restart the filter to make them
effective.

This is because it is not possible for an ISAPI filter to
dynamically change its event registrations - it can ask for
notification of log events only at filter startup.

Some examples: Suppose you start the filter, and have no rules
that use the [U] unmangle flag.  In this case, the filter will
start up, and will not register for log events.  If you then
modify the ini file to use unmangling on one or more rules, the
filter will reload the ini file.  But in this case, unmangling
will not work, as IIRF will not have registered for log event
notifications, and so will not have the opportunity to unmangle
the log.  Restarting the filter allows this change to become
effective.

On the other hand, suppose you have a [U] flag on at least one
active rule, and you have started the filter.  In this case IIRF
will register for log event notifications, and log unmangling
will work properly, though no requests that the filter handles
will be served via the IIS6 kernel-mode cache.  Now suppose you
then change the ini file so that another rule also uses [U].  The
unmangle settings on that changed rule will become active
immediately.  No restart is necessary in this case.

Finally, consider the case where at least one RewriteRule has
[U], and you start the filter (start IIS).  Every use of [U]
should work properly, though again, no requests will be served
from the IIS6 kernel cache.  Then suppose you modify the ini file
and remove all [U] flags.  The filter will continue to receive
SF_NOTIFY_LOG events, and it will continue to behave
correctly.  But in this case, the IIS6 kernel cache will continue to be not
used.  Subsequently, if you then modify the ini file again, and
re-introduce a [U] flag on one or more RewriteRules, the
unmangling will work properly, without restart of IIS, because
log event notifications are already flowing to IIRF.

When in doubt, restart the filter when changing the [U] flag for
any rule. 

If you don't care about the IIS6 kernel cache, and want to avoid
this issue and "enable" log unmangling all the time, then you can
insert a dummy RewriteRule into your ini file, a rule that is
never satisfied, but uses the [U] flag.  This will cause IIRF to
register for log notifications, always.

IIS5 has no kernel mode cache.  If you use IIRF on Windows XP or
Windows 2000, you don't have to worry about this issue.


RewriteCond <test-string> <pattern> [<modifier flag[,...]>]
-------------------------------------------------

When this directive precedes a RewriteRule directive, the
RewriteRule directive is applied only when the condition
supplied in the RewriteCond directive evaluates to true.  When
there are multiple RewreiteCond directives in series, the
RewriteRule directive is applied when the entire chain evaluates
to true.

By default successive RewriteCond directives are linked by a
logical AND. There is an optional modifier_flag [OR] that allows
you to chain the next RewriteCond with a logical OR.  

The evaluation of each RewriteCond is done per-request.  The
test string may include plain text, rule-pattern back references
of the form $N (N=1,2,3...), Condition back references of the
form %N, or references to server variables of the form %{NAME},
as well as the case-folding directives #L #U #E #l #u.





Back References like $n and %n
--------------------------------

Back references in the replacement pattern of the form $n refer
to the matched substrings in the RewriteRule.  This is
consistent with most regular-expression utilities.  IIRF also
supports, within the replacement pattern of the RewriteRule,
back-references to matched substrings in the previously
evaluated condition pattern, using the form %N, where
N=1,2,3,....

The "previously evaluated condition pattern" is not always the
previous RewriteCond in the file, because depending on the
logical operators used, some RewriteCond's will not be evaluated
at all.  

Here's an explanation for why this is so.  For each RewriteCond,
IIRF does this:

1. generate a value for the <test-string>, replacing any Server
   Variables, and back-references to do so.

2. apply the regular expression <pattern> to see if it matches.  

If the regex matches, then the back-references of the form (%1,
%2) become available for the next RewriteCond, or for the
RewriteRule.


Now, suppose you have this rule with these conditions: 

   RewriteCond <test-string-A>  <pattern-A>  [OR]
   RewriteCond <test-string-B>  <pattern-B>
   RewriteCond <test-string-C>  <pattern-C>
   RewriteRule ^/blah$   %1

  
In English, this translates to: if (A OR (B AND C)), then apply
the RewriteRule.

Supposing that RewriteCond A evaluates to TRUE, then RewriteCond
B and RewriteCond C will never be evaluated.  Therefore any
back-references in the RewriteRule replacement pattern (like %1
above) will refer to matched substrings (if any) in RewriteCond
A.

Now suppose that RewriteCond A evaluates to FALSE, and both B
and C are true. In this case, any back-references of the form
%1, %2... in <test-string-B> will refer to RewriteCond A - but
they will be invalid references as RewriteCond A evaluated to
false.  On the other hand, back-references of that form in
<test-string-C> will refer to matched substrings from
RewriteCond B, and these will be active and valid.  Finally,
back-refs like %n in the RewriteRule will refer to matched
substrings from RewriteCond C.

In this example, there is no possibility that references like %n
in the RewriteRule replacement string will ever refer to matched
substrings from RewriteCond B, because the order of logical
evaluation implies that RewriteCond B will never be the most
recently evaluated condition after the overall condition set
evaluates to TRUE. Get it?


Order of evaluation of RewriteCond and RewriteRule
--------------------------------------------------

It may be a bit counter-intuitive at first, so I will repeat
here for clarity: it is possible to include back-references of
the form $n in the test-string for RewriteCond.  This is because
the RewriteRule pattern is evaluated, but not applied, BEFORE
the associated chained set of RewriteConds.  The $n in any
RewriteCond test string will refer to matched substrings from
the pattern in the RewriteRule.  Only if the RewriteRule pattern
matches, and any associated chain of RewriteCond statements
evaluates to TRUE, will the RewriteRule actually be applied.


Server Variable References
--------------------------

The NAME for the server variable must be one of the following: 
    APPL_MD_PATH
    APPL_PHYSICAL_PATH
    AUTH_PASSWORD
    AUTH_TYPE
    AUTH_USER
    CERT_COOKIE
    CERT_FLAGS
    CERT_ISSUER
    CERT_KEYSIZE
    CERT_SECRETKEYSIZE
    CERT_SERIALNUMBER
    CERT_SERVER_ISSUER
    CERT_SERVER_SUBJECT
    CERT_SUBJECT
    CONTENT_LENGTH
    CONTENT_TYPE
    GATEWAY_INTERFACE
    HTTPS
    HTTPS_KEYSIZE
    HTTPS_SECRETKEYSIZE
    HTTPS_SERVER_ISSUER
    HTTPS_SERVER_SUBJECT
    INSTANCE_ID
    INSTANCE_META_PATH
    LOCAL_ADDR
    LOGON_USER
    PATH_INFO
    PATH_TRANSLATED
    QUERY_STRING
    REMOTE_ADDR
    REMOTE_HOST
    REMOTE_USER
    REQUEST_METHOD
    SCRIPT_NAME
    SERVER_NAME
    SERVER_PORT
    SERVER_PORT_SECURE
    SERVER_PROTOCOL
    SERVER_SOFTWARE
    URL
    HTTP_ACCEPT
    HTTP_ACCEPT_LANGUAGE
    HTTP_CONNECTION
    HTTP_HOST
    HTTP_REFERER
    HTTP_USER_AGENT
    HTTP_ACCEPT_ENCODING

Special Value: 
    REQUEST_FILENAME

If you use something other than one of these values, then the
string will not be interpreted - it will evaluate to the name.
For example, if you pass %{THIS_IS_NOT_VALID}, the RewriteCond
will evaluate at runtime to "THIS_IS_NOT_VALID" which is
probably not what you want.

The special value "REQUEST_FILENAME" is not a server variable,
but it can be referenced within a RewriteCond using the
server variable syntax (eg %{REQUEST_FILENAME} ).  This special name
will evaluate to the physical path of the requested URL, which
may or may not correspond to an existing file.


Example 10: 

  RewriteCond %{REMOTE_ADDR}   ^(?!127.0.0.1)([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3})(.*)$
  RewriteRule  ^/(?!redirected.htm)(.*)$      /redirected.htm


The above condition evaluates to true when the server-variable
"REMOTE_ADDR" evaluates to an ip address which is NOT
127.0.0.1. The ?! is a zero-width negative lookahead, and the
(.*) at the end of the regex is to catch any rubbish that
sometimes appears in that variable.  The rule following the
condition says, for any URL which is not "redirected.htm", map
it to "redirected.htm".  This prevents endless re-writing. (You
could also prevent endless rewriting with an [L] modifier flag).
You might use this pair of condition and rule to redirect any
externally originated requests to the IIS server on WinXP.
Local requests would still be honored.

Example 11:

    RewriteCond %{HTTP_REFERER} ^(?!HTTP_REFERER) 
    RewriteCond %{HTTP_REFERER} ^(?!https?://(?:www\.)mysite\.net/)   [I]
    RewriteCond %{HTTP_REFERER} ^(?!https?://203\.0?30\.0?46\.178/)
    RewriteCond %{HTTP_REFERER} ^(?!https?://(?:www\.)foo\.com/)      [I]
    RewriteCond %{HTTP_REFERER} ^(?!https?://203\.0?30\.0?46\.181/)
    RewriteRule \.(?:gif|jpg|jpeg|png)$ /blocked.png   [I,L]

    RewriteRule ^blocked\.png$/ blocked.png [I,L]


There are 2 rules.  The first rewrite rule will block direct
image linking, with a list of sites allowed to link.  The rule
pattern says "match anything that ends in a .gif, jpg, jpeg or
png."  IF this match happens, the URL gets rewritten to
blocked.png.  But, this rewriteRule is only in effect if the
RewriteCond chain applies.  In this case, there are five
RewriteCond statements in the chain.  In each case the cond
should read, "when HTTP_REFERER is NOT the given pattern (notice
the ?! in each pattern.  So, when all of these are true, then
the request for an image is blocked.  If any is not true, then
the request for an image is not blocked.

The first RewriteCond that mentions HTTP_REFERER says - if
HTTP_REFERER evaluates to HTTP_REFERER.  This happens in IIRF if
there is no HTTP_REFERER server variable.  So you've got to
handle that in the ruleset.

The second rule just strips trailing slashes. 


----

Note: I haven't tested all of these Server Variables - some of
them may not be set inside the SF_NOTIFY_AUTH_COMPLETE event in
the ISAPI Filter.  The documentation is not clear on this point. 



Modifier flags
-------------------------------------------------

There are two modifier flags supported on a RewriteCond: 

  I = case insensitive matching.  See comments on [I] for 
      RewriteRule.

  OR = combine rule conditions with a logical OR. Without this,
      successive RewriteCond directives are joined by a logical AND.


Example 12: 

  RewriteCond %{HTTP_HOST} ^www.domain1.tw$  [OR]
  RewriteCond %{HTTP_HOST} ^www.domain2.tw$
  RewriteRule (?!^/index.php)(?!.*\/$)(?!.*\.html$)^/(.*)$        /index.php?$1


In English, what this says is, when the incoming URL 
  does not begin with /index.php
  does not end in a slash
  and does not end in a .html
then match everything following the first slash
and rewrite it to prepend index.php? to it. 
and by the way, apply this rule only when the HTTP_HOST matches www.domain1.tw or www.domain2.tw

With this rule, we get these outputs, when the domain name
is www.domain1.tw: 

'/news/2006-04/newsitem.html'       ==> No Rewrite (ends in .html)
'/news/'                            ==> No Rewrite (ends in a slash)
'/news'                             ==> '/index.php?news'
'/foo/bar/bah/'                     ==> No Rewrite (ends in a slash)
'/foo/bar/bah'                      ==> '/index.php?foo/bar/bah'
'/news/index.php/newsitem.html'     ==> No Rewrite (ends in .html)
'/news/index.php/newsitem.js'       ==> '/index.php?news/index.php/newsitem.js'
'/news/index.php/newsitem'          ==> '/index.php?news/index.php/newsitem'
'/news/index.php-04/newsitem.html'  ==> No Rewrite  (ends in .html)
'/news/index.php-04/newsitem.js'    ==> '/index.php?news/index.php-04/newsitem.js'
'/news/index.php-04/newsitem'       ==> '/index.php?news/index.php-04/newsitem'
'/news/foo-index.php/newsitem.html' ==> No Rewrite (ends in .html) 
'/news/foo-index.php/newsitem.js'   ==> '/index.php?news/foo-index.php/newsitem.js'
'/news/foo-index.php/newsitem'      ==> '/index.php?news/foo-index.php/newsitem'




RewriteCond: Special Patterns
-------------------------------------------------

As of v1.2.10, RewriteCond supports some special patterns, as an
alternative to using a regular expression. These are: 

  -d
  Treats the TestString as a pathname and tests if it exists,
  and is a directory.

  -f
  Treats the TestString as a pathname and tests if it exists and
  is a regular file.

  -s 
  Treats the TestString as a pathname and tests if it exists and
  is a regular file with size greater than zero.


These may be particularly useful when employed with the server
variable, PATH_TRANSLATED, which is the translated path of the
request. It is something like REQUEST_FILENAME in Apache
mod_rewrite.  They may also be used with the special value
"REQUEST_FILENAME" that is known within IIRF.  

Each of these special patterns can be logically negated with a !
prepended to the special pattern.  To clarify, !-s evaluates to
TRUE, when the TestString is not a valid file, or when the test
string is a directory, or when the test string is a file of zero
length.


Example 13: 

  RewriteCond %{HTTP_URL}             (/|\.htm|\.php|\.html|/[^.]*)$   [I]
  RewriteCond %{REQUEST_FILENAME}     !-f
  RewriteCond %{REQUEST_FILENAME}     !-d                                  
  RewriteRule ^.*$                    /index.aspx                      [U,L]


This ruleset says, if the URL ends in .htm, .php, or .html (case
insensitive); AND the physical path associated to the URL is not
a file AND it is not a directory, then rewrite the URL to
index.aspx, and parse no more rules. Also, log the original
(un-rewritten) URL in the log file.  I think something close to
this should work for Joomla and OpenSEF, but I don't test those
things so I cannot verify that.


Nota Bene: You should not count on PATH_TRANSLATED to be the
same as REQUEST_FILENAME.  It is not the same, consult the
section in this doc on server variables for more information on
this. In IIS6 there is an additional Server variable called
SCRIPT_TRANSLATED which may be the same as REQUEST_FILENAME.
Ymmv.  Also, as noted elsewhere, REQUEST_FILENAME is NOT an IIS
Server Variable - you won't find it in any other ISAPI, and you
cannot get it from within PHP or ASPX as far as I know.  It is a
pseudo-Server Variable in IIRF, and its value is generated
within IIRF, and known and usable only within IIRF.


Example 14:

  RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
  RewriteRule  ^/$                 /homepage.max.html  [L]


This ruleset says, if the User-Agent is Mozilla, then rewrite to
a special html page.

Note that in some cases HTTP_USER_AGENT is not passed by the
client. This is legal in HTTP.  You should not rely on User-Agent
being non-empty.


Example 15:

  RewriteCond %{SERVER_NAME}          ([^\.]+)\.chiesa\.net$                [I]
  RewriteCond c:\Inetpub\wwwroot\%1   !-d
  RewriteRule ^(.*)$                  /NotFound.htm                         [U,I,L]

  RewriteCond %{SERVER_NAME}          ([^\.]+)\.chiesa\.net$                [I]
  RewriteCond c:\Inetpub\wwwroot\%1   -d
  RewriteRule ^(.*)$                  /common/driver.aspx?url=$1&host=%1    [U,I,L]


This one redirects a request based on the hostname specified in
the request.  If there is no subdirectory under
c:\InetPub\wwwroot with the same name as the hostname specified
in the request, then the first rule fires,and the user gets a
NotFound.htm page. If there is a sub-directory, then the 2nd
rule fires and the incoming request is rewritten to a common
driver.aspx, specifying the hostname (back-ref %1) and the URL
request (back-ref $1) to that driver.

In this way the rewriter changes its behavior depending on the
state of the filesystem underlying the IIS server.  For example,
when you register new users or new hosts, you might create a new
file or directory in the filesystem.  When a request comes in,
the rewriter can check for the file or directory and rewrite
accordingly.  Pretty cool. 



IterationLimit {integer}
-------------------------------------------------

When a URL is matched to a RewriteRule pattern, the default
behavior of IIRF is to recurse - to apply the rules again,
iteratively, until no pattern matches.  (This behavior can be
modified using the [L] flag).   In other words, the
output of a RewriteRule, is processed as input.

The IterationLimit ini-file directive specifies how many times the
rewrite filter will loop on a single URL.  After a URL has been
transformed successfully, the result will be run through the
Rewrite rules again, to be transformed again.  This continues
for a single URL, as many times as necessary, or until the 
IterationLimit is exceeded, whichever comes first.

The IterationLimit is included as a fail-safe mechanism.
Consider the simplest case: It is possible to create a rewrite
rule that generates an output that matches its own input
pattern.  The effect is a logical infinite loop.  It is also
possible to have more complex loops, for example the output of
one rule matches the input of another rule, and vice versa.  

With an infinite loop or cycle in your ini-file Rewrite rules, and
without an IterationLimit, the ISAPI filter would loop
infinitely, and resulting in a stack overflow, and a
denial-of-service in IIS.

The simple solution would be: don't design sets of rules that
induce loops.  But sometimes it can be difficult to determine if
a loop might occur. The IterationLimit removes the potential for
this infinite loop.

The default IterationLimit is 8.  This default applies if you do
not specify an IterationLimit in the ini file.  The default may
or may not be suitable for any particular deployment.  It is not
likely that you will need more iterations, but if you do, change
the limit with the IterationLimit directive.

NB: the IterationLimit does not apply only to the case where the
same RewriteRule is applied to the URL.  It applies to the
number of passes through ALL of the rules. If a URL matches any
Rule, then the rule is applied, the iteration count is
incremented and the IIRF engine does another pass.

Example 16: 

   IterationLimit 5
   RewriteRule ^/([^0-9]*)$  /1/$1
   RewriteRule ^/1/([^0-9]*)$  /2/$1
   RewriteRule ^/2/([^0-9]*)$  /3/$1
   RewriteRule ^/3/([^0-9]*)$  /4/$1
   RewriteRule ^/4/([^0-9]*)$  /5/$1
   RewriteRule ^/5/([^0-9]*)$  /6/$1
   RewriteRule ^/6/([^0-9]*)$  /7/$1

Given the above set of rules, you will get these results:

 '/index.html' ==> '/6/index.html'
 '/1/index.html' ==> '/7/index.html'
 '/2/index.html' ==> '/7/index.html'


The range of valid values for IterationLimit is 1 to 30.  
If you specify an IterationLimit out of this range, the default
value of 8 will be used, and a message will be logged in the log
file.


MaxMatchCount {integer}
---------------------------------------------

The MaxMatchCount directive specifies the maximum number of
matches to collect for each match.  The example regular
expressions in the same ini file have 1 or 2 matches. In more
complex scenarios, an RE might have 8 or 12 matches.  The
MaxMatchCount allows an admin to specify the upper limit for
this number.  The default is 10.

The range of valid values for MaxMatchCount is 4 to 25. 
If you specify an MaxMatchCount out of this range, the default
value of 10 will be used, and a message will be logged in the
log file.



RewriteLog <filename stub>
---------------------------------------------

This directive sets the logfile name. 

The value should specify a fully-qualified filename.  The name
specified in the ini file is used as a stub: to this stub, the filter
appends the process ID (also known as the 'pid') and ".log" to
the provided name to get the final filename.  This is necessary
to allow for multiple worker processes in IIS6.  Example:

   RewriteLog c:\temp\iirf

gives a net logfilename of 

   c:\temp\iirf.1672.log 

if the process ID of the w3wp.exe is 1672.  

You will get multiple logfiles if you have multiple worker
processes.

The file will be created by the ISAPI filter when it handles its
first URL.  If the file path is not valid, or if the ISAPI does
not have permissions to write to the specified file path, then
no logging will be generated.  If you expect to see a logging
file and don't see one, check your paths and permissions.

If you do not include a RewriteLog directive in your ini file,
then you will get no logging at all.  This may be what you want.

As of v1.2.11d, according to a request from AlexanderGross on
CodePlex.com, the RewriteLog directive will now accept log file
stubs that include spaces.  Leading and trailing spaces are
stripped.  For example:

   RewriteLog     c:\Websites and Stuff\web1.out

...gives a net logfilename of 

   c:\Websites and Stuff\web1.out.1882.log


...if the process ID of the w3wp.exe is 1882.  


Special Note:

For the RewriteLog, you should  specify a different directory
from that which contains the .ini file.  

Here is why: IIRF monitors the directory where the .ini file
resides, looking for changes.  Under Windows, it is not possible
to monitor a single file for changes. Instead, the application
must monitor an entire directory tree, and the application is
notified in *any* file in the monitored directory tree,
including in subdirectories, changes.  If your log file and ini
file are in the same directory, or if your log file is in a
subdirectory of the directory for the ini file, then every time
the log file is updated, which of course happens quite often,
IIRF detects a change in a file in the monitored directory tree.
If you have a RewriteLogLevel greater than 2, the file change
watcher then logs some messages, which of course results in a
change in the log file. Again IIRF detects a change in the
directory tree. Again it logs some messages, and the cycle
continues.  As a result, when the log file and the ini file are
in the same directory, there can be a very long cycle of
activity, most of it useless.  Eventually the notifications
cease, but it can cause detrimental effects in the behavior of
IIRF.

Currently IIRF checks to verify that the Logfile does not fall
under the directory for the ini file, and logs a warning message
in the logfile if this occurs.  However, IIRF does not enforce
the recommendation to use separate directory trees.  To avoid
the problem and the warning message, specify a different
directory.



RewriteLogLevel {0,1,2,3,4,5}
---------------------------------

This directive sets the logging level.  a higher number means
more logging: 
  0 - no logging
  1 - a little logging
  2 - a little more
  3 - really verbose logging
  4 - also emit trace on server variable replacement and string 
      replacement
  5 - also include messages on file change events and some other
      minor events of interest.  This is generally not useful
      for end users.


The default is zero.  If you set an out-of-range value for the
log level, you may not get logging. a Non-Zero value is useful
for auditing and monitoring purposes, as well as for giving you
that warm fuzzy feeling, knowing that something good is happening.

Do not use level 5 in production - it can result in large log
files with lots of useless information.  This level is 
useful only for troubleshooting.


RewriteFilterPriority {HIGH|MEDIUM|LOW}
-------------------------------------------------

ISAPI has a concept of filter priority.  In versions of IIRF
1.2.10 and prior, IIRF always registered at the DEFAULT
priority, which was MEDIUM.  Some applications require IIRF to
cooperate with other ISAPIs, which means it needs to have a
different priority than the default.  In most cases, this is not
necessary.  

Example 17:
  RewriteFilterPriority HIGH

If an invalid value is specified for RewriteFilterPriority, the
value used by IIRF will remain unchanged.  The default priority
for IIRF is DEFAULT, which for IIS5 and IIS6 works out to "MEDIUM."

If you do not include a RewriteFilterPriority directive, IIRF
will use the default, which is DEFAULT.  You cannot specify
DEFAULT in the ini file.  If you want DEFAULT for the filter
priority, then just don't use a RewriteFilterPriority directive.

Changes to this directive in the ini file are not effective,
until the IIS server or ISAPI filter is restarted.  This is
because the filter priority is set once, when the ISAPI DLL is
loaded by the server.  If you want to change the filter
priority, be sure to restart the IIS Server or ISAPI filter to
make that change effective.



==================================================================


Unrecognized Directives
---------------------------------

Any unrecognized directives in the INI file will be tolerated
without generating any exception.  So, be careful of spelling.
If you specify

  RWriterule xyz abc

...(notice the missing E) the filter won't do anything except
emit a warning message in the log. If you don't check the log,
you may be none the wiser.

As noted elsewhere, case is not sensitive in the directive name,
so 
  ReWrItERUle
is as good as
  RewriteRule
which is as good as
  rewriterule

All of them are accepted and interpreted.  It is probably
best form and most readable to use RewriteRule.  

Any unrecognized directives will be logged with a WARNING, and
ignored.  Also, incorrectly formatted directives will also
result in a WARNING.  Obviously such errors in the ini file may
materially affect the operation of the filter.  

To be clear, if you have a spelling error or typo in your ini file,
your filter may silently not behave the way you expect it to.
So do be careful and check your logs for WARNINGS, especially
the loading sequence, after every change in your ini file.

One could imagine a directive like "Option Strict" where any
unrecognized or poorly formatted directives are flagged as
ERRORS, not warnings, and cause the filter to barf and refuse to
load.  If anyone has specific requests on this feature, please
do let me know.

There is a tool in the IIRF distribution called TestParse.exe,
which will load an ini file and display the log messages for
parsing the file.  TestParse does not test the operation of the
filter, it only loads the ini file.  It can be handy in foing
first-pass checking on ini file syntax.  



Processing Rules
---------------------------------
Rules are processed in the order they appear in the file.  

This means, if the first RewriteRule rewrites every incoming URL
to "foo", and the next RewriteRule never matches "foo", then the
second RewriteRule will never be satisfied.  

Also, if you set the RewriteLog at the end of the file, logging
won't start until the file has been mostly processed.  This
means you won't see log messages of the parser as it reads in
RewriteRule directives and RewriteCond directives.  Those log
messages can be helpful in troubleshooting or debugging, so I
recommend you put the RewriteLog and RewriteLogLevel directives
in the beginning of the ini file. But you don't have to.



More on Regular Expressions
-------------------------------------------------

The Regular Expression language is a powerful but complex one.
For many people Regular Expressions can be a sort of "dark
magic" but with a little study, and with some useful examples,
most can get productive with regular expressions.

For more information on regular expressions, try searching like: 
http://search.msn.com/results.aspx?q=regular+expressions&FORM=QBRE

or, see the Perl doc:
http://www.perl.com/doc/manual/html/pod/perlre.html

or try a book, like this: 
http://www.amazon.com/exec/obidos/tg/detail/-/1565922573?v=glance

or go to the PCRE doc: 
http://www.pcre.org/pcre.text



Features Not Included
---------------------------------

Apache's mod_rewrite includes the ability to specify local or
remote forwarding.  This is specified with an optional, third
argument to the RewriteRule directive in the .properties file.
This feature of Apache mod_rewrite is not supported by Ionic's
ISAPI rewrite filter.

IIRF does not do forward or reverse proxying, like Apache's
mod_proxy.

Unlike the combination of Apache's mod_rewrite and mod_proxy,
IIRF is a simple and basic rewriting filter. Once a request is
received within an IIS, IIRF can change the request to
"something else", but the request stays on the box, and within
the given IIS server on the box.  Redirects can be forwarded off
the box, but these forward actions are not transparent - they
are client-side redirects.  See the doc for the [R] modifier
above for more details.


Check the Examples Directory
---------------------------------
In the examples directory there are a number of ini files that
show how to do various things.  When trying to figure out how to
use IIRF, It may be worthwhile to just browse those examples to
see if you get some ideas.



Building the Filter
---------------------------------

If you'd like to compile it yourself, you can use the C++ compiler
that ships with Visual Studio 2005, or you can also use the free
version of the Microsoft C++ compiler and tools, called the
Microsoft Visual C++ 2005 Express.  It is available here:

  http://msdn.microsoft.com/vstudio/express/visualc/

If you use the VC++ Express, then you will also need to download
and install the Microsoft Windows Platform SDK, which includes
headers and include files used by the build.


Summary:
To build the filter, you need these pre-requisites: 

1. a build tool; Either: 
 - the Microsoft Visual C++ 2005 Express, plus
   the Microsoft Windows Platform SDK (core files plus IIS SDK).
   The latter includes headers and lib files used by this project.

or:
 - Microsoft Visual Studio 2005.  
   This one includes the headers and libs you need.


Either of the above also includes a make utility, nmake.exe . 


2.
 - a PCRE statically linked library, pcre.lib plus the pcre.h
   header file.  These are included in the IIRF
   distribution. You can also download them directly from www.pcre.org. 


NOTE:
After you arrange the pre-requisites, you must modify the
makefile for IIRF to specify the locations of PCRE and the
PlatformSDK libraries.

Finally, Run nmake.




Building PCRE
---------------------------------

IIRF includes a pre-built binary version of the PCRE library, so
it is not required that you download or build a PCRE library to
use IIRF.  However, you may wish to download and build PCRE
yourself.  To download it, go to: http://www.pcre.org/

The build procedure for PCRE on Windows is not
well documented, but it wasn't difficult for me to get the build
to work. You can use one of the MS C++ compilers.  If you wish
to build PCRE on Windows, you will need to
create your own PCRE makefile.  I've included the modified
makefile I used, in this zip file.  IIRF do not include any
source code for PCRE.

As of Friday, 01 Feb 2008, IIRF uses PCRE version 7.6.  This is
the current version of PCRE at this time.

 


Compatibility
---------------------------------

This URL re-writer works with any web application logic,
including but not limited to: Cold Fusion (CFM), Active Server
Pages (ASP), ASP.NET, JSP, PHP, as well as static files like
CSS, JPG, HTM, xml, and so on.

Compatibility issues may arise with other ISAPI filters.  
Let me know if you run into problems.



Testing
---------------------------------

You can test your sets of rules against sample URLs by using the
included TestDriver program.  Source for that is also included.   The
TestDriver links with the ISAPI filter, and asks it to apply the
Rewrite rules to a given set of sample URLs.  The sample Urls
are obtained from SampleUrls.txt, and the rewrite rules are
obtained from the ini file, as normal.  (The ini file name
derives from the name of the ISAPI DLL; by default it works out
to be IsapiRewrite4.ini ).  

When you run the TestDriver.exe, the ISAPI reads the ini file as
normal to determine the Logging level (0,1,2,3).  But, the
logfile is overridden - all logging info is sent to stdout, the
console.

Beginning with v1.2.2, the TestDriver program accepts a -d
switch, which tells it where to load the ini and SampleUrls.txt
file. In this way, you can run the testdriver against multiple
independent rulesets and url sample sets.  Within the <tests>
directory in the distribution zipfile, there are several
subdirectories which illustrate the point.  Example: 

load the ini file and test the SampleUrls.txt in dir
"tests\CaseInsensitive" :

   testdriver -d tests\CaseInsensitive

Please note: the testdriver does not run within the context of
an HTTP server, and so does not work with HTTP Server variables.
In particular, if you use RewriteCond in the ini files that you
test with testdriver.exe, and those RewriteCond statements
reference Server variables (eg %{HTTP_URL}) , those RewriteCond
statements will not behave in the testDriver the same way they
will behave in an ISAPI.  Likewise, if you reference server
variables in the replacement pattern, it won't work the way you
might hope.  In general, it is difficult to use testdriver to
evaluate any ruleset that relies on HTTP Server variables.


Querying the Version of IIRF
---------------------------------
Since v1.2.12d, there is an IirfVersion.exe utility shipped in
the IIRF package.  Run this utility to print out the version of
the IIRF library you are using. It's easiest if you copy this
exe into the same dir as you copy isapirewrite4.dll .



License
---------------------------------

Ionic's ISAPI Rewrite Filter (IIRF) is an add-on to IIS that can
rewrite URLs.  IIRF and its documentation is distributed under
the Microsoft Permissive License.  See the License.txt file for
full details. 

IIRF depends upon PCRE, which is licensed independently and
separately.  Consult the License.pcre.txt file for details.



Futures
---------------------------------

I welcome feedback on this.  Let me know if you've used it,
and how it went.  Let me know of bugs you find or troubles you
have.  Let me know what other features you would like to see. 

Doo all this on the IIRF site:
   www.codeplex.com/IIRF





Bugs
---------------------------------
 - Not well tested on clustered IIS.
 - Unicode?  what's unicode?
 - Incorrectly formatted ini files makes the parser choke and the ISAPI will crash. 
 - Performance has not been well measured. 
 - There is no MRU cache employed for URL re-writing. 
 - No rollover of text-based Log files
 - The filter silently tolerates syntax errors in the INI file. 
   This behavior should be settable. (eg, option strict)
 - Not under source control. 
 - Not possible to test RewriteCond with server variables via
   TestDriver.exe, or, to test [U] modifier with TestDriver.exe





Fixed Bugs / Change History
---------------------------------

(See ReleaseNotes.txt)




Updates
---------------------------------

Check for the latest updates at: 
 http://www.codeplex.com/IIRF




Related
---------------------------------

IIS 6 Resource Kit
  http://www.microsoft.com/downloads/details.aspx?familyid=56fc92ee-a71a-4c73-b628-ade629c89499&displaylang=en

IISRewrite
  http://www.qwerksoft.com/products/iisrewrite/ 

ISAPI_Rewrite
  www.isapirewrite.com

Mod_Rewrite 2
  http://www.iismods.com/

PCRE
 http://www.pcre.org

Visual C++ 2005 Express
  http://msdn.microsoft.com/vstudio/express/visualc/

Microsoft Platform SDK download (March 2006 Edition)
  http://www.microsoft.com/downloads/details.aspx?FamilyId=E15438AC-60BE-41BD-AA14-7F1E0F19CA0D&displaylang=en  



Thanks
-Dino

dpchiesa@hotmail.com
