Internet Marketing and Web Development Resources
Home Site Map About Contact

301 Redirection Functions writting in Active Server Pages (Classic ASP)

Table of Contents

Helicon ISAPI Rewrite for MS IIS

Introduction


Return to Search Engine Optimization Resources Home

The following source code is for webmasters who: (1) do not have access or permission to set up and configure an ISAPI filter on MS Windows IIS web server; or (2) do not feel comfortable with the complicated rewrite regular expression syntax most ISAPI filters use.

In several cases the URL can be rewritten or a page redirected without an ISAPI filter, but there are many cases in which you cannot avoid them.

You can learn more about basic 301 redirection and URL rewrites (mod rewrites via .htaccess on Apache web server) here at Cumbrowski.com at my webmaster resources page. There you will also find ISAPI filters and other related tools for Microsoft's Internet Information Server (IIS).

I decided to make some of my ASP code available to the public in response to comments on my article at Search Engine Journal about URL rewrites. I recommend that you read the post and also the comments, if you haven't already done so, because both the article and comments contain useful information on this subject.


Can Do and Can't Do with ASP


Return to Search Engine Optimization Resources Home

The following source code is written in classic active server pages (ASP) and not ASP.NET, but it should not be a problem to port it to the .NET platform.

ASP has a disadvantage compared to PHP, because it does not have the equivalent of $_SERVER['REQUEST_URI'] which returns the path of the original request (excluding the domain name). This allows a much nicer solution than the workaround in ASP for the problem of the default script in a directory and the different URLs from which the same script/page can be accessed.

This brings me to the main purpose of the scripts available on this page. The purpose is primarily related to the issue of Canonical URLs and duplicate content. For a rewrite of the URL to eliminate all dynamic parameters an ISAPI filter is required. However, simple rules would be necessary (not multiple interdependent rules) if you want to cover all scenarios that require a redirect. As a matter of fact, you don't need a redirection rule in your ISAPI filter, but only a simple rewrite rule that disguises to visitors and search engines the true names of your dynamic scripts.

Helicon Link Freeze for Database Driven Sites

- top -


Source Code Download


Return to Search Engine Optimization Resources Home

You can download the source code of all examples used in this article.
Here is the zip-file with the code: asp301code.zip (right click and select "save as").

Additionally, before each snippet of source code is a link with this icon that refers to the particular piece of source code in plain text format.

- top -


Global Variables


Return to Search Engine Optimization Resources Home

Don't rush into redirecting. Make sure that you keep the number of redirects to the absolute minimum.

You might also want to execute some other code before you do the redirect. This is specifically the case for the code that strips tracking parameters from the URL to redirect to the same page -- without those unique parameters that would be seen as new pages by search engine crawlers. Before you redirect those, the code that is doing the tracking should be executed of course.

Feel free to change the names of the variables throughout the code to match your company or personal coding guidelines.

Figure #1
'global variables for 301 redirect
dim gb301redirect,_               'true/false - true is 301 redirect must be performed
    gs301redirectprotocol,_       'secured (https://) = port 443 or unsecured page = port 80
    gs301redirecthost,_           'the redirect host (or domain)
    gs301redirectpathandscript,_  'the path (sub directories) and script name
    gs301redirectqs,_             'the url parameters or query string
    gs301homehost                 'default host name (only relevant if you have multiple 
                                  'domains pointing to one website)

- top -


Host and Port Determination and Check


Return to Search Engine Optimization Resources Home

Here is a global variable which you need to provide to the script. It is the information about your default host/domain. This is important in two cases.

  1. Canonical URLs; and
  2. Multiple domains, but one site.

The first case would be that your site is accessible via www.mysite.com and mysite.com (without the www.). It might be clear to you that both are the same thing, but it is not clear to search engine spiders. As a matter of fact, you could have a different website on each version, because they are technically two different sites.

The second case is common if you own the .net and .com domain for your site or any other TLD (top level domain) variation or your brand name.

If you have any of those domains point to the same site and return the same content, then you must determine which one will be the default, or primary, one.

Figure #2
  'Home Host - you could also make www.mysite.com the Home host
	'if you prefer users to redirect to http://www.mysite.com 
	'rather than http://mysite.com
	
  gs301homehost = "mysite.com"
	

This function simply double-checks your setting for gs301homehost and serializes it. It also determines whether the current page is called secured or unsecured.

Updated Global Variables
gs301redirectprotocol
gs301redirecthost

Figure #3
'---------------------------------------------------------------------------
' function: sysdetermine301redirhostandprotocol
' parameters: none
'---------------------------------------------------------------------------
' system function - determines the primary and destination host   
' (e.g. www.mysite.com or mysite.com ) and protocol 
' http:// for port 80 and https:// for port 443
'---------------------------------------------------------------------------
sub sysdetermine301redirhostandprotocol()
dim sprimarysitehost

  sprimarysitehost = lcase(gs301homehost)
  sprimarysitehost = replace(sprimarysitehost,"http://","")
  sprimarysitehost = replace(sprimarysitehost,"https://","")
  if right(sprimarysitehost,1) = "/" then
    sprimarysitehost = left(sprimarysitehost,len(sprimarysitehost)-1)
  end if
  gs301redirecthost = sprimarysitehost
	 
  if request.servervariables("SERVER_PORT") = 80 then
    gs301redirectprotocol = "http://"
  end if 
  if request.servervariables("SERVER_PORT") = 443 then
    gs301redirectprotocol = "https://"
  end if	
  	
end sub

This sub module checks whether the current host matches your specified primary host or not.

It triggers a 301 redirect right away, but you can disable that, by simply commenting out the lines "call sysexec301redirect()" and "response.end" by adding a single-quote (') in front of them.

The immediate redirection makes sense if you use tracking where you set cookies. Cookies are bound to a domain. If you set a cookie while the user is still on one of the domains that is not your primary one, the cookie would not be readable to the site after the redirect to the primary host/domain.

It might add an additional 301 redirect, but in some cases this is a smaller problem that a cookie placed on the user's machine without being able to access it again.

Figure #4
'---------------------------------------------------------------------------
' sub: syscheckisprimaryhost
' parameters: none 
'---------------------------------------------------------------------------
' system function - checks if the site host is the same as the primary host
' a 301 redirect should be initiated if the function returns true, because 
' there is either a canonical-url or multiple domains for the same site problem
'---------------------------------------------------------------------------
sub syscheckisprimaryhost()
dim sprimarysitehost, scurrenthost

  sprimarysitehost = lcase(gs301homehost)
  sprimarysitehost = replace(sprimarysitehost,"http://","")
  if right(sprimarysitehost,1) = "/" then
     sprimarysitehost = left(sprimarysitehost,len(sprimarysitehost)-1)
  end if
  scurrenthost = lcase(request.servervariables("HTTP_HOST"))
  if right(scurrenthost,1) = "/" then
     scurrenthost = left(scurrenthost,len(scurrenthost)-1)
  end if

  if scurrenthost <> sprimarysitehost then
     gs301redirectpathandscript = request.servervariables("SCRIPT_NAME")      
     gs301redirectqs = request.querystring
     gb301redirect = true 

     'start immediate redirection code
     call sysexec301redirect()
     response.end
     'end of immediate redirection code

  end if
	
end sub


- top -


Generic 301 Redirect Sub Module


Return to Search Engine Optimization Resources Home

The generic sub module that performs the actual 301 redirect, if gb301redirect = true (meaning one or more rules that require redirecting were met) and if all required information such as the destination host, path and script were provided (also global variable).

Figure #5
'--------------------------------------------------------------------------------
'generic 301 redirect sub 
'requires global variables: gb301redirect , gs301redirectprotocol 
'gs301redirecthost , gs301redirectpathandscript and gs301redirectqs 
'--------------------------------------------------------------------------------
sub sysexec301redirect()
dim s301redirecturl
 
  if gb301redirect = true then
  '301 redirect is enabled
  
    'check that all needed information were provided
    if gs301redirectprotocol <> "" and gs301redirecthost <> "" and _
       gs301redirectpathandscript <> "" then
      
       s301redirecturl = gs301redirectprotocol & gs301redirecthost 
       s301redirecturl = s301redirecturl & gs301redirectpathandscript
       if gs301redirectqs <> "" then
         'querystring 
         s301redirecturl = s301redirecturl & "?" & gs301redirectqs
       end if
        
       response.status = "301 moved permanently"
       response.addheader "location", s301redirecturl
       response.end
    
    end if
		
  end if
 
end sub

- top -


Sample Use of Sub Modules


Return to Search Engine Optimization Resources Home

Here is a little sample where all the current functions I introduced are used together. The current functions are the foundation for more functions that will follow soon.

Figure #6
'global variables for 301 redirect
dim gb301redirect,_               'true/false - true = 301 redirect must be performed
    gs301redirectprotocol,_       'secured (https://) = port 443 or unsecured = port 80
    gs301redirecthost,_           'the redirect host (or domain)
    gs301redirectpathandscript,_  'the path (sub directories) and script name
    gs301redirectqs,_             'the url parameters or query string
    gs301homehost                 'default host name (only relevant if you have  
                                  'multiple domains pointing to one website)
 
gs301homehost = "mysite.com"																	
 
Call sysdetermine301redirhostandprotocol()
Call syscheckisprimaryhost()

- top -


Trailing Slash Versus No Trailing Slash Issue


Return to Search Engine Optimization Resources Home

Note: For this example am I assuming that "default.asp" is the default script for your homepage or for entry pages of subdirectories of your website. You have to adjust the sample source code if your default script has a different name.

Another problem with duplicate URLs is the way Microsoft IIS works when you have a default script specified. IIS responds to requests to the URLs: "http://www.mysite.com", "http://www.mysite.com/" (trailing slash) and "http://www.mysite.com/default.asp" as the same page.

For requests to "http://www.mysite.com" and "http://www.mysite.com/" IIS automatically executes the default script (default.asp). You can avoid references to "http://www.mysite.com/default.asp" but the problem with the trailing slash versus the non-trailing slash version remains.

There is unfortunately nothing in IIS to avoid this behavior.

Adding to the problem is the fact that none of the request server variables or any other system function in ASP allows you to determine which of the three URLs are requested by the user. It always looks like as if the user requests "http://www.mysite.com/default.asp", even if the actual request is "http://www.mysite.com" or "http://www.mysite.com/".

PHP has the function $_Server[REQUEST_URI], but unfortunately there is not an equivalent to this function in ASP.

The Workaround
I have found only one solution to this problem. It is not the prettiest one, but it works.

The solution 301 redirects all requests to "http://www.mysite.com/" and "http://www.mysite.com" to the main URL "http://www.mysite.com/default.asp".

  1. Open IIS Manager, right click on the website and select "properties."
  2. Select the tab "documents" and click "add."
  3. Enter as name for the new default content page "index.asp" and press "ok."
  4. Select "index.asp" and click "move up" until "index.asp" is the first script in the list.
  5. Create the file "index.asp" in all folders, including the website root directory.
  6. The source code of the file "index.asp" looks like this:
Figure #7
<%
Dim s301RedirectHOST, s301RedirectURL

s301RedirectHOST	 = Request.Servervariables("HTTP_HOST") 
s301RedirectURL = "http://" &  s301RedirectHOST & Request.Servervariables("SCRIPT_NAME")
s301RedirectURL = replace(s301RedirectURL,"index.asp","default.asp",1,-1,1)

Response.Buffer = False
Response.Status = "301 Moved Permanently"
Response.AddHeader "Location", s301RedirectURL
Response.End
%> 

Note: If you change all websites on the web server, you can make the above change to IIS on the "Web Sites" folder level to update all sites on the web server at once. Also all new websites created on that server will have this setting by default, if you configure it there.

Conclusion
With this solution and the solutions mentioned earlier, all versions of the homepage can be accessed by a user 301-redirected to one single URL, thus no duplicate URL that does not redirect remains on the website. You can test it out for Cumbrowski.com. Check out the following URLs (Note: I set gs301homehost = "www.cumbrowski.com"):

  1. http://cumbrowski.com
  2. http://cumbrowski.com/
  3. http://cumbrowski.com/default.asp
  4. http://www.cumbrowski.com
  5. http://www.cumbrowski.com/

As you can see are they all being redirected to the "master URL" at "http://www.cumbrowski.com/default.asp".

- top -


URL Duplication Because of URL Parameters for Custom Tracking


Return to Search Engine Optimization Resources Home

Here is a function to remove URL parameters that are used only for tracking -- without changing or removing the parameters you need -- followed by a 301 redirect without those additional parameters to leverage the "link juice" of those links to your page.

Affiliate Tracking URLs

Many custom solutions and in-house solution providers use them, and networks are often adding (optional in most cases) tracking parameters to the landing page URL on your website.

PPC Tracking URLs

PPC URLs are usually not followed by search engine spiders, but you might want to redirect them as well, because you don't know if the user who hits the PPC landing page (with the custom tracking parameters in the URL) will bookmark the page or maybe copy it and put it up on the web somewhere or send it to a friend via email.

Figure #8
Function RemoveFromQueryStr(ByVal strCurrentQueryString, ByVal strParamName)
    Dim strQueryString, strItem, strParamArray

    strParamArray = Split(strCurrentQueryString, "&")
    For Each strItem In strParamArray
        On Error Resume Next
        If Not Ucase(Split(strItem, "=")(0)) = Ucase(strParamName) Then
            strQueryString = strQueryString & strItem & "&"
        Else
          gb301redirect = true
        End If
        On Error Goto 0
    Next

    strQueryString = Replace(strQueryString, "&&", "&")
    RemoveFromQueryStr = strQueryString
End Function

Here is how you use the function in combination with the 301 redirect function, which I provided above.

The variables gs301redirecthost & gs301redirectprotocol were already updated by the function sysdetermine301redirhostandprotocol().

The value for gs301redirectpathandscript was not set unless the function syscheckisprimaryhost() determined that the call was not made to the primary host. I strongly suggest that all tracking URLs used are pointing to the primary host (domain) or things will get a lot more complicated. I will assume in my example that you used the primary host for your tracking URL.

Figure #9
'global variables for 301 redirect
dim gb301redirect,_               'true/false - true = 301 redirect must be performed
    gs301redirectprotocol,_       'secured (https://) = port 443 or unsecured = port 80
    gs301redirecthost,_           'the redirect host (or domain)
    gs301redirectpathandscript,_  'the path (sub directories) and script name
    gs301redirectqs,_             'the url parameters or query string
    gs301homehost                 'default host name (only relevant if you have  
                                  'multiple domains pointing to one website)
																	
gs301homehost = "mysite.com"																	

Call sysdetermine301redirhostandprotocol()
Call syscheckisprimaryhost()

if gs301redirectpathandscript = "" then
  gs301redirectpathandscript = request.servervariables("SCRIPT_NAME")
end if
gs301redirectqs = request.querystring
		
if request.querystring("afid") <> "" then
'Your custom tracking code where you log hits for each afid, set a cookie etc.
'....
end if

'Remove afid tracking URL parameter from Querystring
gs301redirectqs = RemoveFromQueryStr(gs301redirectqs, "afid")

'if afid was found in querystring, gb301redirect is set to true
if gb301redirect = true then
  Call sysexec301redirect()
end if

You can call the function multiple times if you have more than one possible tracking parameter in the URL.

- top -


Planned Sample Code for the Future


Return to Search Engine Optimization Resources Home

I will provide more sample source code with detailed explanations of what it does and where and when you should use it -- and why -- as soon as I can. I am currently quite busy, so please bear with me.

I plan to provide and explain the following:

Sample source code for making URLs nice, descriptive and static with a mix of relatively simple ISAPI filter rules and scripting.

You will require Helicon URLRewrite for those examples.

Helicon ISAPI Rewrite for MS IIS
- top -


Cumbrowski.com Sponsors

See the Advertiser Kit to learn more about sponsorship opportunities at Cumbrowski.com. Press? Download my Media Kit.

Email Alert & Newsletter (privacy) My Blog Posts and Newsletter (read)


Enter your email address:

or ReveNews - Carsten Cumbrowski - Feed