Virtual Hosting: PAC
Virtual Hosting: Home | Name based | PAC | Browsers and PAC | Making it portable | Issues |
PAC and Portability |
On the previous page I covered name-based virtual hosting. It uses the local machine's Hosts file to resolve domain names. To run a portable development server you need to edit the new target PC’s Hosts file. This page looks at resolving this issue using a PAC file and a portable browser, making the server completely portable.
PAC allows you to simulate a DNS server locally, with one line per CNAME entry. Unlike the hosts file it is dynamic. PAC is a standard, uses a single file and is supported by all new browsers.
Ever had problems testing sites with a mix of relative, root relative and absolute links? Ever wanted to test cross-site interlinking? The following trio may be what you are looking for. Uniform Server, portable (Firefox or Opera) and PAC make an ideal test environment, all on a USB memory stick.
In the light of issues raised overall, Firefox portable is the best option.
Background
Testing multi-web sites is relatively easy. First create a virtual host section for each site in the Apache configuration file. Use the hosts file on your machine to resolve the web site names to IP address. That’s it; finished. Suppose you do not have access to the host file. What alternatives are there?
If you use only relative links on your site, you can use the Apache alias and re-map. However if your sites are using absolute or root-relative links, this method will fail.
So what other methods are there for resolving IP addresses? A local DNS server would do nicely, even allow you to enter MX records. That seems a bit of overkill, since all we want to do is convince our browser to pick up pages from a different server masquerading as the real server. Enter the world of proxy servers.
PAC
Web browsers can be configured to use a proxy server, allowing the use of files or other resources available on a different server.
This process is automated with a Proxy Auto-Configuration (PAC) file. Sounds complicated, but not really. The PAC file is a simple text file containing a few instructions.
Just tell your browser where to find it by setting the appropriate options. Your browser reads this file when it is re-started and whenever it needs to resolve an IP address.
Any special instructions are executed before your browser attempts to resolve an IP address. This is why PAC is so powerful.
PAC file
The PAC file is a JavaScript consisting of a single function. This function receives two parameters (url and host).
|
|
|
The full URL being accessed e.g.: http://wiki.uniformserver.com/index.php/Main_Page |
|
The hostname extracted from the URL. It is the string between :// and the first : or / after that e.g. |
|
The return value is a string describing the configuration. |
Return Value:
The JavaScript function must return a single string. If the string is null, no proxies will be used. The string can contain any of the following blocks, separated by a semicolon:
DIRECT | Connections should be made directly, without any proxies. |
PROXY host;port | The specified proxy should be used. It's this return value we are interested in |
SOCKS host;port | The specified SOCKS server should be used. |
There are a number of predefined functions you can use. We are interested in only two: shExpMatch and dnsDomainIs.
If these do not suit your needs, you can easily find more information on the Internet. This is worth a read, and the site has more PAC info: Navigator Proxy Auto-Config File Format.
Compare function
This function compares two strings. I think the only special character it accepts is the wildcard character * (matches one or more characters). It's not a limitation and probably makes it easier to use. The function has this format:
shExpMatch(str, shexp)
|
any string to be compared for example the URL or the hostname. |
|
the expression to compare against can use the wildcard character. |
The function returns true if the string matches the specified expression.
Examples:
shExpMatch("http://home.unicenter.com/site1/index.html", "*site1*") is true.
shExpMatch("http://home.unicenter.com/site2/index.html", "*site1*") is false.
The above is just an example. Replace the fixed string with a variable such as the url, for example:
(shExpMatch(url, "*site1*");
Any url passed to the above function containing the string site1 (anywhere) will produce true.
The result can be filtered using an if statement. If true do something else continue onto the next line of code.
Filter |
---|
if (shExpMatch(url,"*site1*")) return "PROXY 127.0.0.1"; |
When the comparison is true, the something to do is to return an IP address of a proxy server. The url our browser was looking for can be found on the proxy server 127.0.0.1 (that's our local test server). It's this return value that resolves the IP address hence the browser is happy and fetches the information.
Complete PAC file
Add this filter to the PAC function and we have our very own DNS resolver, with the ability to define any CNAME that we wish.
test.pac File |
---|
function FindProxyForURL(url, host) |
Note: If a match is not found the function returns a null value. This means the poor old browser needs to do a little more work to resolve the IP address. It checks the hosts file, then any local DNS server, and as a last resort puts a request onto the Internet to a DNS server.
PAC and Hosts file
From the previous page we have the following entries in the Hosts file:
- 127.0.0.1 www.my_site1.fredtest.mine.nu
- 127.0.0.1 www.my_site2.fredtest.mine.nu
- 127.0.0.1 www.ric.com
With a PAC file, specific strings can be targeted. We are interested in resolving domain names and not what is typed into a browser. I have highlighted in bold these domain names. There are only two domains to resolve: mine.nu and ric.com hence our PAC file requires only two lines as follows:
test.pac File |
---|
function FindProxyForURL(url, host) { if (shExpMatch(url,"*.mine.nu/*")) return "PROXY 127.0.0.1"; if (shExpMatch(url,"*.ric.com/*")) return "PROXY 127.0.0.1"; return ""; } |
Alternative function
If you do not like using wild cards, you can use the function dnsDomainIs to directly target a domain name.
dnsDomainIs(host, domain)
|
is the hostname from the URL e.g http://wiki.uniformserver.com/index.php/Main_Page |
|
is the domain name to test the hostname against e.g. .uniformserver.com |
Returns true if the domain of hostname matches.
test1.pac File |
---|
function FindProxyForURL(url, host) { if (dnsDomainIs(host,".mine.nu")) return "PROXY 127.0.0.1"; if (dnsDomainIs(host,".ric.com")) return "PROXY 127.0.0.1"; return ""; } |
Mimic Hosts file
You can mimic the host file as follows:
test2.pac File |
---|
function FindProxyForURL(url, host) { if (shExpMatch(url,"http://www.my_site1.fredtest.mine.nu/*")) return "PROXY 127.0.0.1"; if (shExpMatch(url,"http://www.my_site2.fredtest.mine.nu/*")) return "PROXY 127.0.0.1"; if (shExpMatch(url,"http://www.ric.com/*")) return "PROXY 127.0.0.1"; return ""; } |
Feedback from the forum (27-6-07)
This was posted by figment88 and provides another interesting way to use a PAC file; you can read the full post here Uniform Forum. All I have done is cut and paste to here.
I wanted to add an extra tip on top of the UniCenter tutorial. The tutorial shows you how to setup a proxy file so you can have name based virtual hosts without modifying the current computer's HOST file. The examples in the tutorial require you to modify your proxy file (*.pac) to add a line for every new virtual host. In addition, the examples use wildcard matching, so if you name your local site "example" and the real site is "example.com" the browser might not let you load both.
I made a simple proxy file that solves both these issues
figment88.pac |
---|
function FindProxyForURL(url, host) { if(isPlainHostName(host)) return "PROXY 127.0.0.1"; return "DIRECT"; } |
The isPlainHostName looks for hosts that have a dot. So, I always name my local version of a website as a single word; e.g,
site1 is site1.com
site2 is site2.com
Comment: My original pac file contained wildcard matching, not intentional since I especially wanted to target each site and prevent my browser looking on the Internet. I have included both versions for completeness. In contrast figment88 wants to view his development site locally and the published version hence his neat solution.
Summary
The above was just a quick introduction to the PAC file; it is much more powerful and worth further investigation. Search the Internet for more information. I have only covered what we need for our purpose. The test.pac file is about as complex as it gets.
On the next page I show how to plumb the PAC file into your browser.
Ric |