Fog Creek Software
Discussion Board

Web site virtual roots

Say I have the base URL and I want to setup "virtual" links like so:

The '/Company*' suffix should not be a virtual root or a subdirectory.  All virtual "links" would point to the same page, which would be able to see what "link" was actually entered:


    ' Hypothetical code for Default.asp    
    Dim currentLink
    currentLink = ...

    Call Response.Write("Hello " & currentLink)


Is this possible? 

My platform is IIS running ASP or ASP.NET.

Kevin Sanders
Sunday, February 8, 2004

It's entirely possible.  Check out the SCRIPT_NAME environment variable to figure out what name your application was called by, which will include the path.

Clay Dowling
Sunday, February 8, 2004

SCRIPT_NAME didn't work for me because I'm actually specifying a valid directory or page.  I ended up mapping the 404 (Page Not Found) error to a custom page.  Inside the custom page I parsed the "virtual root" from the QUERY_STRING and did a lookup to see if it was any of the values I was expecting.  If it wasn't I just displayed a page not found error.

I'm not really sure that's the right way to do it, but it works.

I guess my original example was not spelled out well enough, so here's a followup:

Say you have an online pet store where the content is the same but you allow individual mom and pop pet stores to customize the site layout/product selection.  I want to be able to allow the mom and pop pet stores to have URLs like so:

Based on the mnemonic (PetesPets, FredsPets, etc) they would get redirected to a common page (say Default.asp) and they would be identified by a URL parameter, cookie or Session value.

    Option Explicit

    ' Parse the query string.
    Dim QueryString
    QueryString = Request.ServerVariables("QUERY_STRING")

    Dim RegEx
    Set RegEx = New RegExp
    RegEx.Pattern = "^(\d+);http(s?)://(\w+)/(\w+)/?(.*)$"
    RegEx.IgnoreCase = True
    Dim Matches
    Set Matches = RegEx.Execute(QueryString)
    If Matches.Count > 0 Then
        Dim Match
        Set Match = Matches(0)
        Dim ErrorCode, IsSecure, Domain, RootFolder, RequestedResource
        ErrorCode = Match.SubMatches(0)
        IsSecure = Len(Match.SubMatches(1)) > 0
        Domain = Match.SubMatches(2)
        RootFolder = Match.SubMatches(3)
        RequestedResource = Match.SubMatches(4)
        ' Check to see if the root folder is actually a pet store mnemonic.
        Dim StoreId
        StoreId = ""
        Select Case RootFolder
            Case "FredsPets"
                StoreId = "789"
            Case "PetesPets"
                StoreId = "456"
            Case "SamsPets"
                StoreId = "123"
        End Select
        If Len(StoreId) > 0 Then
            Call Response.Redirect("Store.asp?StoreId=" & Server.URLEncode(StoreId))
        End If
    End If        

        <title>404 - File not found!</title>
        404 - File not found!  You're not wanted here, please go somewhere else.

It's probably not the direction I'll go (no real projects require it yet), just playing around.

Kevin Sanders
Monday, February 9, 2004

I use the PATH_INFO variable. If you have a page at:

Then you can call:

This still loads page.asp, but the server environment variable PATH_INFO contains "/more/stuff/page2.asp".

I use this to store entire web sites in a database. The code simply looks up the provided path, loads the data, and returns it with the appropriate MIME type.

Caliban Tiresias Darklock
Monday, February 9, 2004

how do you record the PATH_INFO into the IIS logs? or does it work differently for ASP pages than for CGI pages (e.g. the moinmoin wiki software)

Monday, February 9, 2004

I'm not sure what you're asking. On Apache, the PATH_INFO is included in the URL that gets written to the access.log; I don't have ready access to an IIS server to check, but it seems to me that IIS would be smart enough to do the same thing. I'd be very surprised if it didn't end up going in there somehow.

Since you probably have a file that doesn't check PATH_INFO, try calling your default.asp file as "default.asp/some/more/stuff" and look at the log to see what comes out.

Caliban Tiresias Darklock
Monday, February 9, 2004

This is IIS. It seems to report the URL to the CGI script itself, not the URL of the request.

Example: browse to http;//localhost/mywiki/moin.cgi/RecentChanges. It shows up as

20:03:24 192.168.X.Y DOMAIN\user GET /mywiki/moin.cgi - 200 -

now if there's an image on the page and it's not yet cached by the browser, this will also appear:

20:03:24 192.168.X.Y DOMAIN\user GET /wiki/img/moin-new.gif - 200 http;//localhost/mywiki/moin.cgi/RecentChanges

So the referer info can tell me the first page someone visits on a particular day, or the first page they visit with a particular image, but in general there's no logging of which particular pages they visit within the wiki.

BTW, if you browse to the alternate syntax /mywiki/moin.cgi?RecentChanges, the RecentChanges part will get logged (the query string is the item just before the response code in my log, always '-' above).

Monday, February 9, 2004

Here are two ideas.

1) Create a redirecting virtual directory (or subdirectory).  You won't actually put files in this directory.  Go to the IIS control panel, create a new virtual directory (or subdirectory if you prefer), right click the new directory ("CompanyA", for example), select the option to redirect to a URL and type in the destination URL ("").  When is accessed, IIS will redirect the browser to the appropriate store.asp URL. 

2) Create the individual companies as subdirectories with a default.asp file that is empty other than including an ASP script with the real code:

  <!-- #include virtual="/inc/store.asp" -->

store.asp can analyze the path to determine which store to display or you can pass a parameter to some subprocedure in store.asp that does all the work:

  <!-- #include virtual="/inc/store.asp" -->
  <% Call Store "CompanyA" %>

Method 1 is quick and easy but I prefer method 2 (and particularly the second variation) because it can allow more flexibility.  For example, if CompanyB decides they want their store to appear at, you can just point to the right server and you're ready to go without them getting upset about turning into  Method 2 also has the advantage of not requiring access to some way of configuring the redirection which may make it desirable with hosting plans that don't make this easy. 

Monday, February 9, 2004

If you want it to be logged, you're out of luck. IIS doesn't log PATH_INFO anywhere, and there's no way to make it do so. You would have to roll your own access tracking system, either by redirecting to another resource and checking referrers, or by keeping your own access log of PATH_INFO contents. This is probably too much work for someone who couldn't be arsed to type a URL in his browser and see what happened.

I'm going to go uninstall IIS now.

Caliban Tiresias Darklock
Monday, February 9, 2004

i think the 'web bug' is the easiest to implement for my scenario (change the template and it's done). probably won't bother because i don't really care, but wantted to know if someone knew a hidden setting to make IIS log that information by itself.

Monday, February 9, 2004

*  Recent Topics

*  Fog Creek Home