1 |
/* redirect - simple redirection CGI program |
2 |
** |
3 |
** Copyright © 1995 by Jef Poskanzer <jef@acme.com>. |
4 |
** All rights reserved. |
5 |
** |
6 |
** Redistribution and use in source and binary forms, with or without |
7 |
** modification, are permitted provided that the following conditions |
8 |
** are met: |
9 |
** 1. Redistributions of source code must retain the above copyright |
10 |
** notice, this list of conditions and the following disclaimer. |
11 |
** 2. Redistributions in binary form must reproduce the above copyright |
12 |
** notice, this list of conditions and the following disclaimer in the |
13 |
** documentation and/or other materials provided with the distribution. |
14 |
** |
15 |
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
** SUCH DAMAGE. |
26 |
*/ |
27 |
|
28 |
/* Three steps to set up a redirection: |
29 |
** 1. Make sure your web server is set up to allow CGI programs. |
30 |
** 2. Make a symbolic link from the file you want to redirect, |
31 |
** pointing at this program in the CGI bin directory. |
32 |
** 3. Add an entry to the file ".redirects" in the directory where your |
33 |
** http server runs CGI programs. For most servers, this is the |
34 |
** directory where the given CGI program lives. The format of the |
35 |
** file is a bunch of lines with a filename, whitespace, and the new |
36 |
** URL. For example: |
37 |
|
38 |
/test/oldfile.html http://www.acme.com/test/newfile.html |
39 |
|
40 |
** The easiest way to figure out precisely what filename to put into |
41 |
** .redirects is to set up the symlink and then click on it. You'll get |
42 |
** back a "404 Not Found" page which includes the filename as received by |
43 |
** the redirect program, and that's what you want to use. |
44 |
** |
45 |
** Note: this is designed for thttpd (http://www.acme.com/software/thttpd/) |
46 |
** and using it with other web servers may require some hacking. A possible |
47 |
** gotcha is with the symbolic link from the old file pointing at this |
48 |
** script - servers other than thttpd may not allow that link to be run |
49 |
** as a CGI program, because they don't check the link to see that it |
50 |
** points into the allowed CGI directory. |
51 |
** |
52 |
** Note two: It would be really cool to have this program look for |
53 |
** the .redirects file in the same directory as the file being redirected, |
54 |
** instead of in the binaries directory. Unfortunately, this appears |
55 |
** to be impossible with the information CGI gives, plus the non-standardized |
56 |
** but widespread practice of running CGI programs in the directory where |
57 |
** the binary lives. Perhaps CGI 1.2 will address this. |
58 |
*/ |
59 |
|
60 |
#include <sys/types.h> |
61 |
|
62 |
#include <stdio.h> |
63 |
#include <stdlib.h> |
64 |
#include <string.h> |
65 |
|
66 |
#include "config.h" |
67 |
|
68 |
|
69 |
static char* argv0; |
70 |
|
71 |
|
72 |
static void |
73 |
internal_error( char* reason ) |
74 |
{ |
75 |
char* title = "500 Internal Error"; |
76 |
|
77 |
(void) printf( "\ |
78 |
Status: %s\n\ |
79 |
Content-type: text/html\n\ |
80 |
\n\ |
81 |
<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\ |
82 |
<BODY><H2>%s</H2>\n\ |
83 |
Something unusual went wrong during a redirection request:\n\ |
84 |
<BLOCKQUOTE>\n\ |
85 |
%s\n\ |
86 |
</BLOCKQUOTE>\n\ |
87 |
</BODY></HTML>\n", title, title, title, reason ); |
88 |
} |
89 |
|
90 |
|
91 |
static void |
92 |
not_found( char* script_name ) |
93 |
{ |
94 |
char* title = "404 Not Found"; |
95 |
|
96 |
(void) printf( "\ |
97 |
Status: %s\n\ |
98 |
Content-type: text/html\n\ |
99 |
\n\ |
100 |
<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\ |
101 |
<BODY><H2>%s</H2>\n\ |
102 |
The requested filename, %s, is set up to be redirected to another URL;\n\ |
103 |
however, the new URL has not yet been specified.\n\ |
104 |
</BODY></HTML>\n", title, title, title, script_name ); |
105 |
} |
106 |
|
107 |
|
108 |
static void |
109 |
moved( char* script_name, char* url ) |
110 |
{ |
111 |
char* title = "Moved"; |
112 |
|
113 |
(void) printf( "\ |
114 |
Location: %s\n\ |
115 |
Content-type: text/html\n\ |
116 |
\n\ |
117 |
<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\ |
118 |
<BODY><H2>%s</H2>\n\ |
119 |
The requested filename, %s, has moved to a new URL:\n\ |
120 |
<A HREF=\"%s\">%s</A>.\n\ |
121 |
</BODY></HTML>\n", url, title, title, script_name, url, url ); |
122 |
} |
123 |
|
124 |
|
125 |
int |
126 |
main( int argc, char** argv ) |
127 |
{ |
128 |
char* script_name; |
129 |
char* path_info; |
130 |
char* cp; |
131 |
FILE* fp; |
132 |
char *star; |
133 |
char buf[5000], file[5000], url[5000]; |
134 |
|
135 |
argv0 = argv[0]; |
136 |
|
137 |
/* Get the name that we were run as, which is the filename being |
138 |
** redirected. |
139 |
*/ |
140 |
script_name = getenv( "SCRIPT_NAME" ); |
141 |
if ( script_name == (char*) 0 ) |
142 |
{ |
143 |
internal_error( "Couldn't get SCRIPT_NAME environment variable." ); |
144 |
exit( 1 ); |
145 |
} |
146 |
|
147 |
/* Append the PATH_INFO, if any. This allows redirection of whole |
148 |
** directories. |
149 |
*/ |
150 |
path_info = getenv( "PATH_INFO" ); |
151 |
if ( path_info != (char*) 0 ) |
152 |
{ |
153 |
cp = (char*) malloc( strlen( script_name ) + strlen( path_info ) + 1 ); |
154 |
if ( cp == (char*) 0 ) |
155 |
{ |
156 |
internal_error( "Out of memory." ); |
157 |
exit( 1 ); |
158 |
} |
159 |
(void) sprintf( cp, "%s%s", script_name, path_info ); |
160 |
script_name = cp; |
161 |
} |
162 |
|
163 |
/* Open the redirects file. */ |
164 |
fp = fopen( ".redirects", "r" ); |
165 |
if ( fp == (FILE*) 0 ) |
166 |
{ |
167 |
internal_error( "Couldn't open .redirects file." ); |
168 |
exit( 1 ); |
169 |
} |
170 |
|
171 |
/* Search the file for a matching entry. */ |
172 |
while ( fgets( buf, sizeof(buf), fp ) != (char*) 0 ) |
173 |
{ |
174 |
/* Remove comments. */ |
175 |
cp = strchr( buf, '#' ); |
176 |
if ( cp != (char*) 0 ) |
177 |
*cp = '\0'; |
178 |
/* Skip leading whitespace. */ |
179 |
cp = buf; |
180 |
cp += strspn( cp, " \t" ); |
181 |
/* Check for blank line. */ |
182 |
if ( *cp != '\0' ) |
183 |
{ |
184 |
/* Parse line. */ |
185 |
if ( sscanf( cp, "%[^ \t\n] %[^ \t\n]", file, url ) == 2 ) |
186 |
{ |
187 |
/* Check for wildcard match. */ |
188 |
star = strchr( file, '*' ); |
189 |
if ( star != (char*) 0 ) |
190 |
{ |
191 |
/* Check for leading match. */ |
192 |
if ( strncmp( file, script_name, star - file ) == 0 ) |
193 |
{ |
194 |
/* Got it; put together the full name. */ |
195 |
strcat( url, script_name + ( star - file ) ); |
196 |
/* XXX Whack the script_name, too? */ |
197 |
moved( script_name, url ); |
198 |
exit( 0 ); |
199 |
} |
200 |
} |
201 |
/* Check for exact match. */ |
202 |
if ( strcmp( file, script_name ) == 0 ) |
203 |
{ |
204 |
/* Got it. */ |
205 |
moved( script_name, url ); |
206 |
exit( 0 ); |
207 |
} |
208 |
} |
209 |
} |
210 |
} |
211 |
|
212 |
/* No match found. */ |
213 |
not_found( script_name ); |
214 |
exit( 1 ); |
215 |
} |