Virtual URLs with Apache and Lasso: saving the environment variables

Introduction

This article describes virtual URLs, and how to configure your Apache web server, Lasso server, and application to process and route requests for virtual URLs to your website. It also explores Apache HTTP Server environment variables and four implementations of virtual URLs for both Lasso 8 and 9.

Why use virtual URLs?

Virtual URLs are used in web application frameworks to route the requested URL to your application, which in turn parses the request as parameters to be passed into the code. For example when browsing to the URL http://www.mysite.com/news/2014/10/19/, the web framework would parse the request URI /news/2014/10/19/, and route it to a "news" application, which in turn would search and return any news articles published on October 19, 2014. Similarly, the request for http://www.mysite.com/news/2014/ would return all articles published during the year 2014.

Because of this URL dispatch (a term used commonly in Python), we can do away with the ugliness of GET parameters in HTTP requests, like this:

http://www.mysite.com/?page=news.html&year=2014&month=10&day=19

and do this instead:

http://www.mysite.com/news/2014/10/19/

Usually virtual URLs do not have a file extension. This combined with the omission of GET parameters helped coin the term "clean URLs", which is synonymous to "virtual URLs" in this context.

Virtual URLs do not map to actual files or directories that exist on the file system.

Virtual URLs also improve search engine ranking, and they improve usability because the are easier for users to parse, remember, and manipulate.

Prerequisites

It is assumed that you have already installed and configured Apache 2.2 or later and Lasso 8 or 9 with the stock installation.

Note

After running through this article, if you are unable to get virtual URLs to work, then you probably have some non-default configuration items that conflict with the methods outlined below. Please submit a comment in the Disqus discussion below, and I'll respond as time allows.

Implementation notes

Depending on your Apache version and programming language, your choices for implementing virtual URLs may be limited.

Apache version

For versions of Apache up to and including 2.2.15, your only option is to use mod_rewrite. In Apache 2.2.16, a new directive FallbackResource was introduced.

Both mod_rewrite and FallbackResource define a default URL for requests that don't map to a file or directory that exists on the file system. mod_rewrite requires at least three lines to accomplish this with the use of RewriteRule and RewriteCond directives and -f and -d flags as tests for the existence of a file or directory. FallbackResource requires only a single line, but only if your programming language supports inspection of environment variables. If it does not support it, then a couple of extra lines of configuration are needed.

Apache configuration files

Locate your main Apache configuration file httpd.conf. The path varies according to both operating system and its version and the version of Apache. Usually for Mac it is located at /private/etc/apache2/httpd.conf and for CentOS /etc/httpd/conf/httpd.conf. If you use a package manager on Mac, like macports or homebrew, or a custom installation of Apache, then the location may be different from the standard.

Environment variables

If you are familiar with environment variables whether in Apache or a shell, and you don't care to explore how to display them using PHP, PERL, or Lasso 9, then you might want to skip ahead to Virtual URL options for Lasso. Otherwise continue reading.

The following quoted material from the Apache documentation is helpful to understand what are environment variables and how they are used.

From Environment Variables in Apache.

There are two kinds of environment variables that affect the Apache HTTP Server.

First, there are the environment variables controlled by the underlying operating system. These are set before the server starts. They can be used in expansions in configuration files, and can optionally be passed to CGI scripts and SSI using the PassEnv directive.

Second, the Apache HTTP Server provides a mechanism for storing information in named variables that are also called environment variables. This information can be used to control various operations such as logging or access control. The variables are also used as a mechanism to communicate with external programs such as CGI scripts.

Although these variables are referred to as environment variables, they are not the same as the environment variables controlled by the underlying operating system. Instead, these variables are stored and manipulated in an internal Apache structure. They only become actual operating system environment variables when they are provided to CGI scripts and Server Side Include scripts. If you wish to manipulate the operating system environment under which the server itself runs, you must use the standard environment manipulation mechanisms provided by your operating system shell.

"CGI scripts" mentioned above imply programming languages, too, such as Python, PHP, PERL, and Lasso 9, but not Lasso 8. This merits emphasis: Lasso 8 does not return the Apache HTTP Server environment variables.

Lasso 8 can display HTTP request headers through the methods client_headers and a few other methods. We will use this fact to work around the lack of Lasso 8's access to environment variables. But first, we need to know which environment variables are available in Apache.

What's in an Apache HTTP Server environment variable?

To see what are Apache HTTP Server environment variables, we can use a script to display their names and values. Both PHP and PERL are installed on Macs and usually Linux, too, so I will include scripts for these languages in addition to Lasso 9, assuming you have installed it already.

The following PHP script shows all predefined PHP variables from EGPCS (Environment, GET, POST, Cookie, Server).

1
2
<?php
phpinfo(32);

Although that's an easy way to see the Apache environment variables, it also includes arguments and request headers. To display only Apache environment variables, we can use either a Lasso 9 or PERL script.

Here is the Lasso 9 script.

1
2
3
4
5
[
web_request->fcgiReq->requestParams->foreachpair => {^
    #1->first + ' = ' + #1->second + '\n'
^}
]

The PERL script requires a little more work in case your server is not configured to process CGI programs. Save the following PERL script env.pl in the directory where your server expects to find CGI programs.

1
2
3
4
# Linux
/usr/local/apache2/cgi-bin/
# Mac
/Library/WebServer/CGI-Executables/

Contents of env.pl.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/usr/bin/perl
use strict;
use warnings;

print "Content-type: text/html\n\n";
print "<div style='font-family:monospace;'>";
foreach my $key (keys %ENV) {
    print "$key = $ENV{$key}<br>";
}
print "</div>";

Make sure the script has the executable bit set.

1
$ sudo chmod 755 env.pl

You might need to configure your server to allow CGI scripts to run. Apache Tutorial: Dynamic Content with CGI is helpful for most UNIX-based systems, but Mac is a little different. If so, then follow the next steps.

Edit your main Apache configuration file httpd.conf.

Ensure cgi_module is enabled.

1
LoadModule cgi_module modules/mod_cgi.so

Set a ScriptAlias directive to tell Apache that a particular directory is set aside for CGI programs.

1
2
3
4
5
6
# Linux
ScriptAlias /cgi-bin/ /usr/local/apache2/cgi-bin/
# Mac provides this horrendous directive by default
# ScriptAliasMatch ^/cgi-bin/((?!(?i:webobjects)).*$) "/Library/WebServer/CGI-Executables/$1"
# but we can use this one
ScriptAlias /cgi-bin/ /Library/WebServer/CGI-Executables/

Next, explicitly use Options to permit CGI execution in the CGI script directory.

1
2
3
4
5
6
<Directory "/Library/WebServer/CGI-Executables">
    Options +ExecCGI
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>

Finally, load the script in a browser by visiting the following URL.

http://localhost/cgi-bin/env.pl

The following is the expected output.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
SCRIPT_NAME = /cgi-bin/env.pl
SERVER_NAME = localhost
SERVER_ADMIN = you@example.com
HTTP_ACCEPT_ENCODING = gzip,deflate,sdch
HTTP_CONNECTION = keep-alive
REQUEST_METHOD = GET
HTTP_DNT = 1
HTTP_ACCEPT = text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
SCRIPT_FILENAME = /Library/WebServer/CGI-Executables/env.pl
VERSIONER_PERL_PREFER_32_BIT = no
SERVER_SOFTWARE = Apache/2.2.26 (Unix) DAV/2 PHP/5.3.28 mod_ssl/2.2.26 OpenSSL/0.9.8za
QUERY_STRING =
REMOTE_PORT = 64744
HTTP_USER_AGENT = Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36
SERVER_PORT = 80
SERVER_SIGNATURE =
HTTP_PRAGMA = no-cache
HTTP_CACHE_CONTROL = no-cache
HTTP_ACCEPT_LANGUAGE = en-US,en;q=0.8
__CF_USER_TEXT_ENCODING = 0x46:0:0
REMOTE_ADDR = 127.0.0.1
SERVER_PROTOCOL = HTTP/1.1
PATH = /usr/bin:/bin:/usr/sbin:/sbin
REQUEST_URI = /cgi-bin/env.pl
GATEWAY_INTERFACE = CGI/1.1
SERVER_ADDR = 127.0.0.1
DOCUMENT_ROOT = /Library/WebServer/Documents
HTTP_HOST = localhost
VERSIONER_PERL_VERSION = 5.12

Note

For a list of both the standard Apache environment variables and the extended SSI variables, visit Tech Stuff - Apache Environmental Variables.

Here we see all the awesomeness of Apache HTTP Server environment variables. Lines 1 and 24 merit special attention.

SCRIPT_NAME is the pathname of the script being executed, relative to DOCUMENT_ROOT.

REQUEST_URI is the interpreted pathname of the requested document or CGI relative to DOCUMENT_ROOT.

Note that in the above output, the values of SCRIPT_NAME and REQUEST_URI match each other. However in a virtual URL configuration, REQUEST_URI would be something like /news/2014/10/19 and SCRIPT_NAME would be something like /_urlhandler.lasso.

Virtual URL options for Lasso

With most languages, it is trivial to grab the REQUEST_URI environment variable, and parse it in your program. But for Lasso 8, we don't have that luxury. Instead we have two basic options. (Actually, there are several other options, including the use of error.lasso, but this article focuses on Apache.)

  1. Pass the virtual URL through Apache to Lasso, and use define_atbegin to force the context of the URL handler into Lasso's _page_ namespace. Thus response_filepath returns the virtual URL.
  2. Pass the virtual URL through Apache to a Lasso file in the web root, say /_urlhandler.lasso. However in this case, response_filepath returns the path to the file which is being served from the web server root (/_urlhandler.lasso), not the requested and virtual URL. To work around this situation, we can configure Apache to set a custom RequestHeader to the value of the environment variable REQUEST_URI, then extract that value from the custom header for our Lasso 8 web framework or application to parse.

The first option has one implementation in Lasso 8 and requires mod_rewrite. The second option has two implementations, one using mod_rewrite and the other using FallbackResource. The easier implementations use FallbackResource for both Lasso 8 and 9.

FallbackResource and Lasso 8.6 Danger

!DANGER!

Updated Dec 17, 2014. A colleague discovered that FallbackResource does not work with file_exists in Lasso 8. Upon further testing, I found it does not work for file_read either. Therefore I would consider the use of FallbackResource with Lasso 8 to be "experimental" and to be used with extreme caution.

For details read the thread Fallback Resource and file_exists / LP8.6.

Configure Apache to handle virtual URLs

When a web browser sends an HTTP request to Apache, your web server evaluates the requested URL to determine what it should do based on the rules in its configuration. Apache may simply return a static asset that exists on the file system—an image, javascript, CSS file, audio, video, or some other document. Apache may determine that the requested URL does not exist on the file system and return a 404 error code, or it may prompt for authentication.

When we use virtual URLs, however, the URL does not map to a physical resource on the file system. By default, Apache would return a 4xx error code for a virtual URL. But we can change that behavior, and instead hand off the request to an interface (CGI, WSGI, Lasso, and others) between the web server and the code or framework for further processing.

Enable Apache modules

Edit your main Apache configuration httpd.conf file using your favorite editor.

1
2
3
# make a backup copy to be safe
$ sudo cp httpd.conf httpd.conf.bkp
$ sudo nano httpd.conf

Look for the block starting with the following.

1
2
3
#
# Dynamic Shared Object (DSO) Support
#

For Lasso 8, make sure the following lines are uncommented and present to enable the modules. It is not necessary to enable these modules for Lasso 9, unless you cannot use FallbackResource and must use mod_rewrite.

1
2
3
4
5
6
# allows RequestHeader, required by all implementations
LoadModule headers_module libexec/apache2/mod_headers.so
# allows SetEnvIf, required for FallbackResource implementation
LoadModule setenvif_module libexec/apache2/mod_setenvif.so
# allows RewriteCond and RewriteRule, required for mod_rewrite implementations
LoadModule rewrite_module libexec/apache2/mod_rewrite.so

Note

For Lasso 9, we have direct access to the environment variables, so we don't need to modify the HTTP request headers or set custom environment variables. It is rare for Lasso 9 to be deployed on a version of Apache that does not support FallbackResource, so we will not cover the edge case of using mod_rewrite with Lasso 9. There is sufficient transferable information from the Lasso 8 examples for you to hack through it. Essentially, remove configuration that involves setting headers or environment variables.

Configure virtual hosts

Wherever you configure your VirtualHost directives (on Linux probably in httpd.conf, and on Mac extra/httpd-vhosts.conf), choose one of the following implementations, and insert the corresponding Apache configuration directives into your virtual host configuration. If you want to try them all out, create one host per implementation and two Lasso 8 instances, one with a define_atbegin and one without.

1. mod_rewrite with define_atbegin for Lasso 8

In this implementation, an HTTP request is received by Apache. Subject to the RewriteCond that define a virtual URL (lines 10-13), a RewriteRule matches the request URL and passes it through to the lasso8-handler while simultaneously setting the value of a custom Apache environment variable X-REQUEST-URI to the request URL (line 14). Next we clear then set a custom header X-REQUEST-URI to the value of the custom Apache environment variable X-REQUEST-URI if the the environment variable exists, all of which is sent to Lasso for further processing (lines 15 and 16).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<IfModule mod_rewrite.c>
    # Turn mod_rewrite on.
    RewriteEngine on

    # Honor the server-wide rewrite rules if any exist.
    RewriteOptions inherit

    # Lasso gets all virtual files and directories that don't have an
    # extension between 1 and 8 characters long
    RewriteCond %{REQUEST_URI} !^.*\.[^.]{1,8}$
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d [OR]
    RewriteCond %{REQUEST_URI} ^/$
    RewriteRule (.*) - [L,NS,H=lasso8-handler,E=X-REQUEST-URI:$1]
    RequestHeader unset X-REQUEST-URI
    RequestHeader set X-REQUEST-URI %{X-REQUEST-URI}e env=X-REQUEST-URI
</IfModule>

2. mod_rewrite only for Lasso 8

This implementation is exactly the same as the previous, except there are a couple of changes to line 14. Here the RewriteRule matches the request URL, passing it through [PT] to a physical file in the web root /_urlhandler.lasso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<IfModule mod_rewrite.c>
    # Turn mod_rewrite on.
    RewriteEngine on

    # Honor the server-wide rewrite rules if any exist.
    RewriteOptions inherit

    # Lasso gets all virtual files and directories that don't have an
    # extension between 1 and 8 characters long
    RewriteCond %{REQUEST_URI} !^.*\.[^.]{1,8}$
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d [OR]
    RewriteCond %{REQUEST_URI} ^/$
    RewriteRule (.*) /_urlhandler.lasso [L,NS,PT,E=X-REQUEST-URI:$1]
    RequestHeader unset X-REQUEST-URI
    RequestHeader set X-REQUEST-URI %{X-REQUEST-URI}e env=X-REQUEST-URI
</IfModule>

3. FallbackResource for Lasso 8

The comments in this implementation are self-explanatory.

1
2
3
4
5
6
7
8
# If REQUEST_URI environment variable matches the regular expression (.*)
# then set an environment variable X-REQUEST-URI to the value captured by
# the regular expression
SetEnvIf REQUEST_URI (.*) X-REQUEST-URI=$1
# Set a RequestHeader to the environment variable we just set
RequestHeader unset X-REQUEST-URI
RequestHeader set X-REQUEST-URI %{X-REQUEST-URI}e
FallbackResource /_urlhandler.lasso

4. FallbackResource for Lasso 9

In this implementation, because Lasso 9 can access Apache HTTP Server environment variables, we do not need to set a custom header.

1
FallbackResource /_urlhandler.lasso

Restart Apache

When you are done editing the file, save it, then check syntax and restart Apache.

1
2
3
$ sudo apachectl -t
Syntax OK
$ sudo apachectl graceful

Lasso code

1. mod_rewrite with define_atbegin for Lasso 8

In this implementation, a define_atbegin handler is required. This is the only implementation that requires one. Save the following code in a file at /Lasso Professional 8/LassoSites/mysite-#/LassoStartup/urlhandler_atbegin.lasso then restart the Lasso instance. The "magic" comes from namespace_using where we force the context of the URL handler into Lasso's _page_ namespace.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
log_critical('urlhandler_atbegin.lasso handler loading');
protect;
// If /_urlhandler.lasso exists at the site root it will be executed,
// otherwise nothing special happens
    define_atbegin(
        {
            if(file_exists('/_urlhandler.lasso'));
                namespace_using('_page_'); // force normal page context
                    include('/_urlhandler.lasso');
                /namespace_using;
            /if;
        // continue normal page execution
        }
    );

    handle_error;
        log_critical('urlhandler_atbegin.lasso handler error ' + error_msg);
    /handle_error;
/protect;
log_critical('urlhandler_atbegin.lasso handler loaded');
]

Below is the URL handler file. It sets a path relative to the web root, tests client_headers for containing the custom header we set in Apache, and if found it will include a file and return a response in the content body.

Save the following code at /path/to/web/root/_urlhandler.lasso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
[
// This file is called by the atbegin handler, so it is executed before any
// page is being processed.
// It should be placed directly inside the web root.

// Adjust this value so it reflects where the site is located in the web root.
// Must begin and end with "/".

var('siteroot'='/');

if(client_headers >> 'X-REQUEST-URI: /');

    // run site
    content_body = include($siteroot + 'index.lasso');
    content_body -> trim;
    abort;

else;

/if;
]

Below is a sample file that returns values that may be used in a web framework.

Save the following code at /path/to/web/root/index.lasso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>mod_rewrite with define_atbegin for Lasso 8</title>
    <style>
        .mono {font-family: monospace; font-size: 1em;}
    </style>
</head>
<body>
<textarea cols="100" rows="20" class="mono">
[response_filepath]

[client_headers]
</textarea>
</body>
</html>

2. mod_rewrite only for Lasso 8

For the rest of the implementations, a define_atbegin is not needed. Either remove the define_atbegin in the instance's LassoStartup directory or use a site that does not use one.

Below is the URL handler. It is exactly the same as the previous example, except it extracts the value of the custom request header X-REQUEST-URI and sets the variable $path to the value. Save the following code at /path/to/web/root/_urlhandler.lasso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[
// This file should be placed directly inside the web root.

// Adjust this value so it reflects where the site is located in the web root.
// Must begin and end with "/".
var('siteroot'='/');

if(client_headers >> 'X-REQUEST-URI: /');
    var('path') = '***undefined***';
    protect;
        $path = string_findregexp(
                    client_headers,
                    -find='(?im)^X-REQUEST-URI:\\s*(.*)$'
                )->get(2)->trim&;
    /protect;

    // run site
    content_body = include($siteroot + 'index.lasso');
    content_body -> trim;
    abort;

else;

/if;
]

Below is a sample file that returns values that may be used in a web framework. It is exactly the same as the previous example, except that it will return the additional page variable $path or a string to indicate it is undefined. Save the following code at /path/to/web/root/index.lasso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>mod_rewrite only for Lasso 8</title>
    <style>
        .mono {font-family: monospace; font-size: 1em;}
    </style>
</head>
<body>
<textarea cols="100" rows="20" class="mono">
[response_filepath]

[var_defined('path') ? $path | '***undefined***']

[client_headers]
</textarea>
</body>
</html>

3. FallbackResource for Lasso 8

Below is the URL handler. It is exactly the same as the previous example. Save the following code at /path/to/web/root/_urlhandler.lasso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[
// This file should be placed directly inside the web root.

// Adjust this value so it reflects where the site is located in the web root.
// Must begin and end with "/".
var('siteroot'='/');

if(client_headers >> 'X-REQUEST-URI: /');
    var('path') = '***undefined***';
    protect;
        $path = string_findregexp(
                    client_headers,
                    -find='(?im)^X-REQUEST-URI:\\s*(.*)$'
                )->get(2)->trim&;
    /protect;

    // run site
    content_body = include($siteroot + 'index.lasso');
    content_body -> trim;
    abort;

else;

/if;
]

Below is a sample file that returns values that may be used in a web framework. It is exactly the same as the previous example. Save the following code at /path/to/web/root/index.lasso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>FallbackResource for Lasso 8</title>
    <style>
        .mono {font-family: monospace; font-size: 1em;}
    </style>
</head>
<body>
<textarea cols="100" rows="20" class="mono">
[response_filepath]

[var_defined('path') ? $path | '***undefined***']

[client_headers]
</textarea>
</body>
</html>

4. FallbackResource for Lasso 9

Earlier while exploring environment variables, we used web_request->fcgiReq->requestParams->foreachpair to display them. To display a single environment variable, we can use a long form to return a bytes type or a short form to return a string type.

1
2
web_request->fcgiReq->requestParams->find(::REQUEST_URI)
web_request->requestURI

Note

See Reading Request Headers in the LassoGuide or the Lasso Language Reference for web_request methods for a complete list and descriptions.

Below is the URL handler. It's modified for Lasso 9 and instead of testing for client headers, it tests for the environment variable REQUEST_URI. Save the following code at /path/to/web/root/_urlhandler.lasso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[
// This file should be placed directly inside the web root.

// Adjust this value so it reflects where the site is located in the web root.
// Must begin and end with "/".
var(siteroot)='/'

if(web_request->requesturi->size
    // prevent urlhandler from processing Lasso admin and instancemanager
    && !web_request->requesturi->beginswith('/lasso9/')) => {

    // run site
    content_body = include($siteroot + 'index.lasso');
    content_body -> trim;
    abort;

else
}
]

Below is a sample file that returns values that may be used in a web framework. Save the following code at /path/to/web/root/index.lasso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>FallbackResource for Lasso 9</title>
    <style>
        .mono {font-family: monospace; font-size: 1em;}
    </style>
</head>
<body>
<textarea cols="100" rows="20" class="mono">
[response_filepath]

[client_headers]

[web_request->requesturi->type]
[web_request->requesturi]
[web_request->fcgiReq->requestParams->find(::REQUEST_URI)->type]
[web_request->fcgiReq->requestParams->find(::REQUEST_URI)]

[
web_request->fcgiReq->requestParams->foreachpair => {^
    #1->first + ' = ' + #1->second + '\n'
^}
]
</textarea>
</body>
</html>

Knop Project web application framework

Knop supports any of the above virtual URL implementations for either Lasso 8 or 9. For details of how a web framework can process virtual URLs, visit the Knop Project on GitHub.

Acknowledgments

  • Johan Sölve for both initiating the concept of clean URLs at Lasso Summit and creating Knop.
  • Bil Corry for three consecutive posts in the topic URL Design and periods in which he introduces how to set headers to environment variables.
  • Jolle Carlestam for suggesting FallbackResource once or twice.

Did you like this article? Please send me a Gratipay, as little as 25¢ per week!

Updates, suggestions and comments regarding this article may be sent to Steve Piercy, web@stevepiercy.com or comment using Disqus.


Written by Steve Piercy in Apache on Sun, Oct 19, 2014.
Last modified: Wed, Dec 17, 2014
Tags: virtual URL, clean URL, Apache, Lasso, environment variables, mod_rewrite, mod_headers, mod_setenvif, FallbackResource

Comments

comments powered by Disqus