Help with INI

Topics: User Forum
Dec 16, 2009 at 10:29 PM

We are in the final stages of redesigning our entire web environment.

All of our department sites are based on numbers.  Purchasing's department number=9220.

We did this because department names can change but their numbers don't.

We have the following requirements:

Department names rewrite to their number (http://www.company.com/Purchasing/ to http://www.company.com/9220/)
This needs to accomodate the "/" and no "/" (http://www.company.com/Purchasing to http://www.company.com/9220/)
Also internal links need to be rewriten or redirected to the department name.
On the index.asp page is a link to /9220/products.asp and it needs to go to /purchasing/products.asp

So.. we tried the following:

RedirectRule  ^/9220/(.*)$   /purchasing/$1 [R=301]
RewriteRule  ^/purchasing(.*)$   /9220$1 [L]
RewriteRule  ^/purchasing/(.*)$   /9220/$1 [L]

Here's some links to the IT site that shows the problem we are seeing:
http://wwwdev.palmbeach.k12.fl.us/it/
http://wwwdev.palmbeach.k12.fl.us/it

The first one works fine but the second one has problems.  The images don't show up.

ANY help would be much appreciated!!!

Ron

Dec 16, 2009 at 10:39 PM
Edited Dec 16, 2009 at 10:40 PM

Testing this with the FQDN, it worked fine.  We were testing it with the short name http://wwwdev/it and the images did not show up.

Also how do I add the next department?

# Purchasing Department
RedirectRule  ^/9220/(.*)$   /purchasing/$1 [R=301]
RewriteRule  ^/purchasing(.*)$   /9220$1 [L]
RewriteRule  ^/purchasing/(.*)$   /9220/$1 [L]

# Information Technology Department
RedirectRule  ^/9230/(.*)$   /it/$1 [R=301]
RewriteRule  ^/it(.*)$   /9230$1 [L]
RewriteRule  ^/it/(.*)$   /9230/$1 [L]

# Instructional Technology
RedirectRule  ^/9229/(.*)$   /itech/$1 [R=301]
RewriteRule  ^/itech(.*)$   /9229$1 [L]
RewriteRule  ^/itech/(.*)$   /9229/$1 [L]

Do these last 2 create a problem?  does http://wwwdev.palmbeach.k12.fl.us/itech/ activate the rule for ^/it(.*)$ ?  If so then how do I differentiate?  Put ITECH above IT?

Thanks

Ron

Coordinator
Dec 17, 2009 at 1:55 AM
Edited Dec 17, 2009 at 2:09 AM

Yes, there's an overlap between the itech rules and the IT rules.  To avoid it, do as you guessed - Put the itech rules above the IT rules.  The rules are evaluated in the order in which they appear in the file.

Ron, you might be interested in the RewriteMap rule.  It is present in the Apache mod_rewrite which was the philosophical inspiration for IIRF, but the RewriteMap is new in IIRF for v2.1.  If you've never heard of this rule before, it's just a simple a lookup table.  It allows you to specify the map (or lookup table) between numbers and departments in a separate file.  In your case, since you map from numbers to names, and also from names to numbers, you'd need two maps, one for each direction.   Then you need fewer rules, and they are "wildcards".  Like this:


NumbersToNames.txt:

# maps dept numbers to dept names

9920 Purchasing
9230 IT
9229 ITech
# more here

NamesToNumbers.txt:

# maps dept names to dept numbers

purchasing 9920 
it         9230 
itech      9229 
# more here...

IIRF.ini:

# rules

# declare the maps
RewriteMap namesToNumbers  txt:NamesToNumbers.txt
RewriteMap numbersToNames  txt:NumbersToNames.txt

# use the maps in the rules
RedirectRule  ^/([0-9]+)/(.*)$   /${numbersToNames:$1}/$2 [R=301]
RewriteRule  ^/([a-z]+)(.*)$     /${namesToNumbers:#L$1#E|notFound.htm}$1  [L,I]
RewriteRule  ^/([a-z]+)/(.*)$    /${namesToNumbers:#L$1#E|notFound.htm}/$1 [L,I]

# any name that was not found is rewritten to /notFound.htm

You may find RewriteMap helpful if you have lots of departments.  If you have only 3, using RewriteMap is probably more complex than it's worth.   It pays off when you have lots of items in the map.

Also, the first RewriteRule in this case is sort of problematic when using a RewriteMap, because there is no delimiter between the department name (it, itech, purchasing) and the rest of the URL.  Not sure if that is what you intend.  The way I wrote the rule, I assumed that the dept name is all letters (a-z), and the "rest of the string" begins with something other than a-z. 

Also, notice I have used case-folding around the map lookupKey.  These are the #L and #E things.  They just say "fold everything between the #L and the #E to lowercase".   This way the lookups work properly, since the dept names in the NamesToNumbers.txt file are all lowercase.

Read about the RewriteMap directive in the documentation

Dec 17, 2009 at 1:06 PM

Thank you.

I'm trying to implement your solution and I'm having some issues.

Here's my IIRF.ini file:

# rules

# declare the maps
RewriteMap namesToNumbers  txt:IIRFNamesToNumbers.txt
RewriteMap numbersToNames  txt:IIRFNumbersToNames.txt

# use the maps in the rules
RedirectRule  ^/([0-9]+)/(.*)$   /${numbersToNames:$1}/$2 [R=301]
RewriteRule  ^/([a-z]+)(.*)$     /${namesToNumbers:$1}$1  [L,I]
RewriteRule  ^/([a-z]+)/(.*)$    /${namesToNumbers:$1}/$1 [L,I]

 

I removed the notFound.htm piece because it was causing a problem with all the other pages (like index.asp).

My Numbers and Name text files are:

# maps dept numbers to dept names

9920 Purchasing
9230 IT
9229 ITech

AND

# maps dept numbers to dept names

Purchasing  9920
IT               9230
ITech          9229

The rewrites don't seem to work.  When I go to http://wwwdev.palmbeach.k12.fl.us/it or /it/ I get page not found.

Here's the log entry:

Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: actual log file 'c:\inetpub\iirfLogs\iirf.1564.log'
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: ini file: 'D:\DEVNew\Default\Iirf.ini'
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: ini file timestamp: 2009/12/17 08:03:44 Eastern Standard Time
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: line   2: LogLevel = 1
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: WARNING: line 8: unrecognized directive, ignoring it: 'RewriteMap'
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: WARNING: line 9: unrecognized directive, ignoring it: 'RewriteMap'
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: line  12: RedirectRule (rule 1)  '^/([0-9]+)/(.*)$'  '/${numbersToNames:$1}/$2'  [R=301]
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: INFO: line 12: Redirecting to a target that does not include an http(s):// scheme.
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig:                The rule will Redirect to a target on the local machine
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: line  13: RewriteRule (rule 2)  '^/([a-z]+)(.*)$'  '/${namesToNumbers:$1|index.asp}$1'    [L,I]
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: line  14: RewriteRule (rule 3)  '^/([a-z]+)/(.*)$'  '/${namesToNumbers:$1|index.asp}/$1'    [L,I]
Thu Dec 17 08:04:02 -  2136 - ReadSiteConfig: Done reading, found 3 rules (0 errors, 2 warnings) on 15 lines

Coordinator
Dec 18, 2009 at 7:00 AM

Hi Ron,

RewriteMap is new in IIRF for v2.1.  You will need to download the latest version to get this capability. 

Also:  If you don't want index.asp to be rewritten, then just insert a rule than excludes it.  Like this:

# rules

# declare the maps
RewriteMap namesToNumbers  txt:IIRFNamesToNumbers.txt
RewriteMap numbersToNames  txt:IIRFNumbersToNames.txt

# don't rewrite index.asp.  (The dash says "no rewrite" and the [L] says, 
# "don't apply any other rules, either."
RewriteRule ^/index.asp.*$            -  [L]

# use the maps in the rules
RedirectRule  ^/([0-9]+)/(.*)$   /${numbersToNames:#L$1#E}/$2 [R=301]
RewriteRule  ^/([a-z]+)(.*)$     /${namesToNumbers:#L$1#E}$2  [L,I]
RewriteRule  ^/([a-z]+)/(.*)$    /${namesToNumbers:#L$1#E}/$2 [L,I]

With the special filter rule for index.asp, you can re-insert the NotFound thing, in order to handle keys that are not present in the map.

Also, notice I put the case-folding markers in there (#L, #E). What that does is make the captured strings lowercase, before using them as lookup keys in the map. The lookup keys in the map files must then be all lowercase, as well. Are you following? You can't have ITech in the map file; it needs to be "itech". lowercase. If you make the key (ITech, IT, Purchasing, etc) mixed case, then the string in the URL must be mixed case, in order for the lookup to succeed, and that might not always happen. Make sense?

Suppose you don't do the case folding (#L, #E) amd you have ITech in your map file. Suppose you get a URL request like this:

  http://server/ITech/foo
...it will be rewritten successfully. But if you get a URL request like this:
  http://server/itech/foo
...it won't be rewritten. IIRF will lookup "itech" in the map file, and won't find it (case mismatch). See?

If you use all lowercase in the map file, and do case folding on the alphabetic lookup keys, you'll be sure to get a match, regardless of the case used in the URL.

Dec 18, 2009 at 2:11 PM

Thank you.

How do I restrict the rewrites to ONLY what is in the files?

It seems to be rewriting other stuff.  I set the log to LEvel 2 and this is what it shows.  Items in RED, should not be rewriten.

Fri Dec 18 08:59:32 -  3568 - ReadSiteConfig: D:\DEVNew\Default\Iirf.ini(2): LogLevel = 2
Fri Dec 18 08:59:32 -  3568 - ReadSiteConfig: D:\DEVNew\Default\Iirf.ini(8): RewriteMap   namesToNumbers  txt:D:\DEVNew\Default\IIRFNamesToNumbers.txt
Fri Dec 18 08:59:32 -  3568 - ReadTextMap: D:\DEVNew\Default\IIRFNamesToNumbers.txt(3): key(purchasing) value(9920)
Fri Dec 18 08:59:32 -  3568 - ReadTextMap: D:\DEVNew\Default\IIRFNamesToNumbers.txt(4): key(it) value(9230)
Fri Dec 18 08:59:32 -  3568 - ReadTextMap: D:\DEVNew\Default\IIRFNamesToNumbers.txt(5): key(itech) value(9229)
Fri Dec 18 08:59:32 -  3568 - ReadSiteConfig: D:\DEVNew\Default\Iirf.ini(9): RewriteMap   numbersToNames  txt:D:\DEVNew\Default\IIRFNumbersToNames.txt
Fri Dec 18 08:59:32 -  3568 - ReadTextMap: D:\DEVNew\Default\IIRFNumbersToNames.txt(3): key(9920) value(purchasing)
Fri Dec 18 08:59:32 -  3568 - ReadTextMap: D:\DEVNew\Default\IIRFNumbersToNames.txt(4): key(9230) value(it)
Fri Dec 18 08:59:32 -  3568 - ReadTextMap: D:\DEVNew\Default\IIRFNumbersToNames.txt(5): key(9229) value(itech)
Fri Dec 18 08:59:32 -  3568 - ReadSiteConfig: D:\DEVNew\Default\Iirf.ini(17): RewriteRule (rule 1)  '^/(.*).XML.*$'  '-'      [I]
Fri Dec 18 08:59:32 -  3568 - ReadSiteConfig: D:\DEVNew\Default\Iirf.ini(19): RedirectRule (rule 2)  '^/([0-9]+)/(.*)$'  '/${numbersToNames:#L$1#E}/$2'  [R=301]
Fri Dec 18 08:59:32 -  3568 - ReadSiteConfig: INFO: D:\DEVNew\Default\Iirf.ini(19): Redirecting to a target that does not include an http(s):// scheme.
Fri Dec 18 08:59:32 -  3568 - ReadSiteConfig: The rule will Redirect to a target on the local machine
Fri Dec 18 08:59:32 -  3568 - ReadSiteConfig: D:\DEVNew\Default\Iirf.ini(20): RewriteRule (rule 3)  '^/([a-z]+)(.*)$'  '/${namesToNumbers:#L$1#E}$2'    [L,I]
Fri Dec 18 08:59:32 -  3568 - ReadSiteConfig: D:\DEVNew\Default\Iirf.ini(21): RewriteRule (rule 4)  '^/([a-z]+)/(.*)$'  '/${namesToNumbers:#L$1#E}/$2'    [L,I]
Fri Dec 18 08:59:32 -  3568 - ReadSiteConfig: Done reading, found 4 rules (0 errors, 0 warnings) on 46 lines
Fri Dec 18 08:59:32 -  3568 - DoRewrites: Url (no decoding): '/community'
Fri Dec 18 08:59:32 -  3568 - EvaluateRules: Last Rule
Fri Dec 18 08:59:32 -  3568 - DoRewrites: Rewrite Url to: '/${namesToNumbers:community}'
Fri Dec 18 09:00:00 -  3568 - DoRewrites: Url (no decoding): '/'
Fri Dec 18 09:00:00 -  3568 - DoRewrites: No Rewrite
Fri Dec 18 09:00:01 -  3544 - DoRewrites: Url (no decoding): '/pbstyles/splashv2matt.css'
Fri Dec 18 09:00:01 -  3544 - EvaluateRules: Last Rule
Fri Dec 18 09:00:01 -  3544 - DoRewrites: Rewrite Url to: '/${namesToNumbers:pbstyles}/splashv2matt.css'

Coordinator
Dec 18, 2009 at 4:31 PM

> How do I restrict the rewrites to ONLY what is in the files?

You have to construct the rules to eclude the URLs you don't want to rewrite.   The way it works: for each URL that arrives at the filter, each rule is applied, in order, until one matches.

So, consider /community  ..... your rule #1 doesn't match because it has .XML in it.  Rule #2 doesn't match because the pattern there is a series of numbers.  Rule #3 applies, and then "community" is looked up in the namesToNumbers map.  It's not found, so it's rewritten.

Likewise for your /pbstyles/splash.css  URL.  To avoid this, filter those URLs out before Rules #2 and #3.  There's a useful "replacement pattern" that says "don't rewrite" at all - a dash.  When a rule using a single dash character as the replacement pattern matches, then the URL is not rewritten.  If you use the [L] modifier, then no more attempts to rewrite will happen on that URL, thus eliminating it from any further rules.  Make sense?

example

# rules

# declare the maps
RewriteMap namesToNumbers  txt:IIRFNamesToNumbers.txt
RewriteMap numbersToNames  txt:IIRFNumbersToNames.txt

# exclude some URLs from rewrite:
# never rewrite a URL that ends in .css :
RewriteRule  ^/(.*)\.css$     -          [L,I]

# never rewrite a URL that starts with /community:
RewriteRule  ^/community     -          [L,I]

# etc

# use the maps in the rules
RedirectRule  ^/([0-9]+)/(.*)$   /${numbersToNames:$1}/$2 [R=301]
RewriteRule  ^/([a-z]+)(.*)$     /${namesToNumbers:$1}$1  [L,I]
RewriteRule  ^/([a-z]+)/(.*)$    /${namesToNumbers:$1}/$1 [L,I]

 
Dec 18, 2009 at 8:04 PM

We've been playing with this all day and are very close...  But...

We had to ditch the:

RewriteRule  ^/([a-z]+)(.*)$     /${namesToNumbers:$1}$1  [L,I]
RewriteRule  ^/([a-z]+)/(.*)$    /${namesToNumbers:$1}/$1 [L,I]

And replace it with:

RewriteRule ^/(it)/(.*)$  /${namesToNumbers:#L$1#E|#L$1#E}/$2 [L,I]
RewriteRule ^/(purchasing)/(.*)$ /${namesToNumbers:#L$1#E|#L$1#E}/$2 [L,I]
RewriteRule ^/(mwbe)/(.*)$  /${namesToNumbers:#L$1#E|#L$1#E}/$2 [L,I]
RewriteRule ^/(bob)/(.*)$  /${namesToNumbers:#L$1#E|#L$1#E}/$2 [L,I]

Because the lookups wern't working properly.

Here's the whole file:

RewriteLog c:\inetpub\iirfLogs\iirf
RewriteLogLevel 2
RewriteEngine ON

# rules

# Automatically add the trailing /
RedirectRule ^/([^.?]+[^.?/])$ /#L$1#E/ [R=301]

# declare the maps
RewriteMap namesToNumbers  txt:D:\DEVNew\Default\IIRFNamesToNumbers.txt
RewriteMap numbersToNames  txt:D:\DEVNew\Default\IIRFNumbersToNames.txt

# Exclude CSS
RewriteRule ^/(.*).css$             -  [L,I]

# Redirect number folders
RedirectRule  ^/([0-9]*)/(.*)$   /${numbersToNames:#L$1#E}/$2 [R=301]

# Rewrite Name URLs to numbers
#RewriteRule ^/(.*)/(.*)$  /${namesToNumbers:#L$1#E|$1}/$2 [L,I]
RewriteRule ^/(it)/(.*)$  /${namesToNumbers:#L$1#E|#L$1#E}/$2 [L,I]
RewriteRule ^/(purchasing)/(.*)$ /${namesToNumbers:#L$1#E|#L$1#E}/$2 [L,I]
RewriteRule ^/(mwbe)/(.*)$  /${namesToNumbers:#L$1#E|#L$1#E}/$2 [L,I]
RewriteRule ^/(bob)/(.*)$  /${namesToNumbers:#L$1#E|#L$1#E}/$2 [L,I]

Now our last problem is that if you put a number folder that does not exist in the Map files then it redirects to a URL like this:

http://wwwdev2.palmbeach.k12.fl.us/$%7BnumbersToNames:9243%7D/ 

We tride the following change in the RedirectRule and it took the Or as a literal.

RedirectRule  ^/([0-9]*)/(.*)$   /${numbersToNames:#L$1#E|$1}/$2 [R=301]

We assumed that adding the |$1 would say "If not found then send to it's original destination"

IT sent to:

http://wwwdev2.palmbeach.k12.fl.us/$1/ 

Thoughts?

Thank you very much for all your help.

Ron

Coordinator
Dec 18, 2009 at 8:38 PM
Edited Dec 18, 2009 at 8:40 PM

YES -

Apply a RewriteCond to the rule that uses the map.   like this:

# Redirect number folders, if found in the map
RewriteCond  ${numbersToNames:$1|NotFound}   !NotFound   
RedirectRule  ^/([0-9]*)/(.*)$   /${numbersToNames:$1}/$2 [R=301]

What it does: The Redirect rule applies only when the first segment of the URL path is found in the map file.   When the first segment is numeric but is not found in the map, then the condition evaluates to FALSE, and the redirectrule does not apply.  The string ${numbersToNames:$1|NotFound} says "lookup whatever $1 evaluates to, in the map, and replace it with whatever you look up.  If the value of $1 is not found as a key in the map, then replace with the string" NotFound".  The RewriteCond then compares that to !NotFound, in other words, the condition is true only when the result of the lookup is NOT NotFound  => when the key is present in the map.

Also, you don't need the case folding in this case. The $1 in this case is a series of numeric digits, so case-folding will never change it. You only need case-folding when the key, the thing you're looking up in the map, has alpha characters in it.

 

ps: I'm interested in finding out what you mean by "the lookups weren't working properly".  If you're happy with your rules, that's all fine.  But I'm guessing that there's a better way to do what you want. Maybe with a RewriteCond there, too.

 

Dec 18, 2009 at 9:55 PM

Again,

Thank you.

I'm going to implement the condition and let you know.

The issue with the lookups is that we have many "exceptions" like /community and we can't know what people will do in the future.  The number folders we control 100%.

Just a thought.  Could I do the same condition with the lookups?

RewriteCond  ${namesToNumbers:$1|NotFound}   !NotFound
RewriteRule  ^/([a-z]+)/(.*)$    /${namesToNumbers:#L$1#E}/$2 [L,I]

Thanks

Ron

Dec 18, 2009 at 10:09 PM


I think we did it.

Final file that seems to work in all our situations:

RewriteLog c:\inetpub\iirfLogs\iirf
RewriteLogLevel 2
RewriteEngine ON

# rules

RedirectRule ^/([^.?]+[^.?/])$ /#L$1#E/ [R=301]

# declare the maps
RewriteMap namesToNumbers  txt:D:\DEVNew\Default\IIRFNamesToNumbers.txt
RewriteMap numbersToNames  txt:D:\DEVNew\Default\IIRFNumbersToNames.txt

# Exclude CSS
RewriteRule ^/(.*).css$             -  [L,I]

# Redirect number folders, if found in the map
RewriteCond  ${numbersToNames:$1|NotFound}   !NotFound  
RedirectRule  ^/([0-9]*)/(.*)$   /${numbersToNames:$1}/$2 [R=301]

# Rewrite URLs if found in the map
RewriteCond  ${namesToNumbers:$1|NotFound}   !NotFound
RewriteRule  ^/([a-z]+)/(.*)$    /${namesToNumbers:#L$1#E}/$2 [L,I]

Coordinator
Dec 18, 2009 at 11:55 PM
Edited Mar 4, 2010 at 3:18 PM

Ron, terrific, glad you're making progress.  Your ini file looks good.

If I were you, I'd want to be sure that the rules work for many cases of URLs - both correct "expected" URLs, and also broken, incorrect, or unexpected URLs.  "Visible" URLs like the homepage, but also "invisible" ones like image requests, or requests for CSS, script, and whatever else.

To do this, IIRF includes a tool, TestDriver.exe.  Once you have your rules set, you can automate the testing of a large number of incoming URLs through the rules, without every submitting a request to the actual web server.  The tool is documented in the .chm file.  Running it will give you confidence that you've covered all the bases with the rules set up the way they are.