216 lines
6.4 KiB
C
216 lines
6.4 KiB
C
/* redirect - simple redirection CGI program
|
|
**
|
|
** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
** SUCH DAMAGE.
|
|
*/
|
|
|
|
/* Three steps to set up a redirection:
|
|
** 1. Make sure your web server is set up to allow CGI programs.
|
|
** 2. Make a symbolic link from the file you want to redirect,
|
|
** pointing at this program in the CGI bin directory.
|
|
** 3. Add an entry to the file ".redirects" in the directory where your
|
|
** http server runs CGI programs. For most servers, this is the
|
|
** directory where the given CGI program lives. The format of the
|
|
** file is a bunch of lines with a filename, whitespace, and the new
|
|
** URL. For example:
|
|
|
|
/test/oldfile.html http://www.acme.com/test/newfile.html
|
|
|
|
** The easiest way to figure out precisely what filename to put into
|
|
** .redirects is to set up the symlink and then click on it. You'll get
|
|
** back a "404 Not Found" page which includes the filename as received by
|
|
** the redirect program, and that's what you want to use.
|
|
**
|
|
** Note: this is designed for thttpd (http://www.acme.com/software/thttpd/)
|
|
** and using it with other web servers may require some hacking. A possible
|
|
** gotcha is with the symbolic link from the old file pointing at this
|
|
** script - servers other than thttpd may not allow that link to be run
|
|
** as a CGI program, because they don't check the link to see that it
|
|
** points into the allowed CGI directory.
|
|
**
|
|
** Note two: It would be really cool to have this program look for
|
|
** the .redirects file in the same directory as the file being redirected,
|
|
** instead of in the binaries directory. Unfortunately, this appears
|
|
** to be impossible with the information CGI gives, plus the non-standardized
|
|
** but widespread practice of running CGI programs in the directory where
|
|
** the binary lives. Perhaps CGI 1.2 will address this.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "config.h"
|
|
|
|
|
|
static char* argv0;
|
|
|
|
|
|
static void
|
|
internal_error( char* reason )
|
|
{
|
|
char* title = "500 Internal Error";
|
|
|
|
(void) printf( "\
|
|
Status: %s\n\
|
|
Content-type: text/html\n\
|
|
\n\
|
|
<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
|
|
<BODY><H2>%s</H2>\n\
|
|
Something unusual went wrong during a redirection request:\n\
|
|
<BLOCKQUOTE>\n\
|
|
%s\n\
|
|
</BLOCKQUOTE>\n\
|
|
</BODY></HTML>\n", title, title, title, reason );
|
|
}
|
|
|
|
|
|
static void
|
|
not_found( char* script_name )
|
|
{
|
|
char* title = "404 Not Found";
|
|
|
|
(void) printf( "\
|
|
Status: %s\n\
|
|
Content-type: text/html\n\
|
|
\n\
|
|
<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
|
|
<BODY><H2>%s</H2>\n\
|
|
The requested filename, %s, is set up to be redirected to another URL;\n\
|
|
however, the new URL has not yet been specified.\n\
|
|
</BODY></HTML>\n", title, title, title, script_name );
|
|
}
|
|
|
|
|
|
static void
|
|
moved( char* script_name, char* url )
|
|
{
|
|
char* title = "Moved";
|
|
|
|
(void) printf( "\
|
|
Location: %s\n\
|
|
Content-type: text/html\n\
|
|
\n\
|
|
<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
|
|
<BODY><H2>%s</H2>\n\
|
|
The requested filename, %s, has moved to a new URL:\n\
|
|
<A HREF=\"%s\">%s</A>.\n\
|
|
</BODY></HTML>\n", url, title, title, script_name, url, url );
|
|
}
|
|
|
|
|
|
int
|
|
main( int argc, char** argv )
|
|
{
|
|
char* script_name;
|
|
char* path_info;
|
|
char* cp;
|
|
FILE* fp;
|
|
char *star;
|
|
char buf[5000], file[5000], url[5000];
|
|
|
|
argv0 = argv[0];
|
|
|
|
/* Get the name that we were run as, which is the filename being
|
|
** redirected.
|
|
*/
|
|
script_name = getenv( "SCRIPT_NAME" );
|
|
if ( script_name == (char*) 0 )
|
|
{
|
|
internal_error( "Couldn't get SCRIPT_NAME environment variable." );
|
|
exit( 1 );
|
|
}
|
|
|
|
/* Append the PATH_INFO, if any. This allows redirection of whole
|
|
** directories.
|
|
*/
|
|
path_info = getenv( "PATH_INFO" );
|
|
if ( path_info != (char*) 0 )
|
|
{
|
|
cp = (char*) malloc( strlen( script_name ) + strlen( path_info ) + 1 );
|
|
if ( cp == (char*) 0 )
|
|
{
|
|
internal_error( "Out of memory." );
|
|
exit( 1 );
|
|
}
|
|
(void) sprintf( cp, "%s%s", script_name, path_info );
|
|
script_name = cp;
|
|
}
|
|
|
|
/* Open the redirects file. */
|
|
fp = fopen( ".redirects", "r" );
|
|
if ( fp == (FILE*) 0 )
|
|
{
|
|
internal_error( "Couldn't open .redirects file." );
|
|
exit( 1 );
|
|
}
|
|
|
|
/* Search the file for a matching entry. */
|
|
while ( fgets( buf, sizeof(buf), fp ) != (char*) 0 )
|
|
{
|
|
/* Remove comments. */
|
|
cp = strchr( buf, '#' );
|
|
if ( cp != (char*) 0 )
|
|
*cp = '\0';
|
|
/* Skip leading whitespace. */
|
|
cp = buf;
|
|
cp += strspn( cp, " \t" );
|
|
/* Check for blank line. */
|
|
if ( *cp != '\0' )
|
|
{
|
|
/* Parse line. */
|
|
if ( sscanf( cp, "%[^ \t\n] %[^ \t\n]", file, url ) == 2 )
|
|
{
|
|
/* Check for wildcard match. */
|
|
star = strchr( file, '*' );
|
|
if ( star != (char*) 0 )
|
|
{
|
|
/* Check for leading match. */
|
|
if ( strncmp( file, script_name, star - file ) == 0 )
|
|
{
|
|
/* Got it; put together the full name. */
|
|
strcat( url, script_name + ( star - file ) );
|
|
/* XXX Whack the script_name, too? */
|
|
moved( script_name, url );
|
|
exit( 0 );
|
|
}
|
|
}
|
|
/* Check for exact match. */
|
|
if ( strcmp( file, script_name ) == 0 )
|
|
{
|
|
/* Got it. */
|
|
moved( script_name, url );
|
|
exit( 0 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* No match found. */
|
|
not_found( script_name );
|
|
exit( 1 );
|
|
}
|