Add Frank Hecker plugins to general.
[matthijs/upstream/blosxom-plugins.git] / general / slashredir
1 # Blosxom Plugin: slashredir
2 # Author(s): Frank Hecker <hecker@hecker.org>
3 # Version: 0.4
4 # Documentation: See the bottom of this file or type: perldoc slashredir
5
6 package slashredir;
7
8 use strict;
9
10 use CGI qw/:standard :netscape/; 
11
12
13 # --- Configurable variables -----
14
15 my $debug = 1;                          # set to 1 to print debug messages
16
17 # --------------------------------
18
19
20 use vars qw!$redirecting!;              # 1 if we are redirecting, 0 if not
21
22
23 sub start {
24     warn "slashredir: start\n" if $debug > 1;
25
26     $redirecting = 0;
27
28     # Activate this plugin only when doing dynamic page generation.
29     return $blosxom::static_or_dynamic eq 'dynamic' ? 1 : 0;
30 }
31
32
33 sub filter {
34     my ($pkg, $files_ref) = @_;
35
36     warn "slashredir: filter\n" if $debug > 1;
37
38     warn "slashredir: \$path_info: '" . $blosxom::path_info . "'\n"
39         if $debug > 0;
40     warn "slashredir: path_info(): '" . path_info() . "'\n"
41         if $debug > 0;
42
43     # We need a copy of the original PATH_INFO, prior to Blosxom having
44     # parsed it, because we need to see the trailing slashes stripped by
45     # Blosxom and also want the full path including date information.
46
47     my $path = path_info();
48
49     # We check to see if the URI is for an entry page and redirect if the URI
50     # has a trailing slash. Otherwise we check to see if a trailing slash
51     #  needs to be added or removed and redirect if needed.
52     #
53     # Note: We use $blosxom::path_info to check for the presence of a
54     # file extension because the extension may not have been present in the
55     # original URI but might have been added by the extensionless plugin.
56     # (That also implies that this plugin must run after extensionless runs.)
57
58     if ($blosxom::path_info =~ m!\.!) {
59         if ($path =~ m!/$!) {
60             $path =~ s!/+$!!;           # strip *all* trailing slashes
61             redirect($path, "Trailing slash(es) not needed");
62         }
63     } elsif ($path !~ m!/$!) {
64         $path .= '/';                   # add one trailing slash
65         redirect($path, "Adding trailing slash");
66     } elsif ($path =~ m!//+$!) {
67         $path =~ s!//+$!/!;             # remove redundant slash(es)
68         redirect($path, "Removing redundant trailing slash(es)");
69     }
70     1;
71 }
72
73
74 sub skip {
75     warn "slashredir: skip\n" if $debug > 1;
76
77     return $redirecting;                # skip story generation if redirecting
78 }
79
80
81 sub redirect {
82     my ($path, $error_msg) = @_;
83
84     my $uri = "$blosxom::url$path";
85     $uri .= "?" . $ENV{QUERY_STRING} if $ENV{QUERY_STRING};
86
87     warn "slashredir: redirecting to '$uri', '$error_msg'\n"
88         if $debug > 0;
89
90     my $redir_msg = qq!, redirecting to <a href="$uri">$uri</a>.\n!;
91     $blosxom::output = $error_msg . $redir_msg;
92     print "Status: 301\n";
93     print "Location: $uri\n";
94     $redirecting = 1;
95 }
96
97 1;
98
99 __END__
100
101 =head1 NAME
102
103 Blosxom plugin: slashredir
104
105 =head1 SYNOPSIS
106
107 Have Blosxom force a redirect if a URI is not in canonical form with respect
108 to trailing slashes.
109
110 =head1 VERSION
111
112 0.4
113
114 =head1 AUTHOR
115
116 Frank Hecker <hecker@hecker.org>, http://www.hecker.org/
117
118 =head1 DESCRIPTION
119
120 This plugin checks to see whether the requested URI has one or more
121 trailing slashes and if necessary does a browser redirect to the
122 canonical form of the URI. More specifically, URIs for the blog root,
123 categories, and date-based archives should have one (and only one)
124 trailing slash, while URIs for individual entry pages should not have
125 a trailing slash.
126
127 For example, if you request the URI
128
129   http://www.example.com/blog/foo
130
131 where "foo" is a category, this plugin will force a redirect to the
132 URI
133
134   http://www.example.com/blog/foo/
135
136 This plugin essentially causes Blosxom to emulate the default behavior
137 of the Apache web server. The underlying idea is that URIs for Blosxom
138 pages should have trailing slashes if and only if there are (or could
139 be) other URIs for other pages "underneath" the URI in question.
140
141 Thus an individual entry page with a URI of the form
142 ".../entry.flavour" (or ".../entry" if using the extensionless plugin)
143 should not have a trailing slash, because URIs of the form
144 ".../entry.html/foo" (or ".../entry/foo" with extensionless) don't and
145 won't return anything meaningful. However a category page with a URI
146 of the form ".../category" could refer to additional pages with URIs
147 of the form ".../category/foo.html (or ".../category/foo/entry"), and
148 hence the canocical form of the category's URI should be
149 ".../category/".
150
151 Similarly, date-based archive pages with URIs like ".../2004" or
152 ".../2004/10" could have subsidiary URIs for months or days
153 respectively; while days are not subdivided further, per-day archive
154 pages could be requested in non-default flavours, e.g.,
155 ".../2004/10/14/index.rss" (as could per-year and per-month pages as
156 well, of course). Hence for date-based archive pages the canonical
157 form of the URI should also include a trailing slash if the default
158 flavour is being requested.
159
160 Note that using this plugin makes most sense if you are also using URI
161 rewriting rules to hide use of "/cgi-bin/blosxom.cgi" and support URIs
162 similar to those traditionally used to access normal directories and
163 files. This plugin can be used in conjunction with the extensionless
164 plugin, but does not assume or require its use. (See also below.)
165
166 This plugin was inspired by the redirect plugin by Fletcher T. Penny
167 http://www.blosxom.com/plugins/general/redirect.htm and adapts a bit
168 of its code.
169
170 =head1 INSTALLATION AND CONFIGURATION
171
172 Copy this plugin into your Blosxom plugin directory. You do not
173 normally need to rename the plugin; however see the discussion below.
174
175 You can change the value of the variable C<$debug> to 1 if you need to
176 debug the plugin's operation; the plugin will print to the web
177 server's error log the original path component of the URI and the new
178 URI if redirection is to be done.
179
180 This plugin supplies a filter and skip subroutine and can normally
181 coexist with other plugins with filter subroutines. However this
182 plugin needs to be run after the extensionless plugin, since it needs
183 the file extension (provided by extensionless if not already present)
184 to distinguish between individual entry pages and other pages.
185
186 Finally, note that this plugin is sensitive to the exact URI rewriting
187 rules you might have configured (e.g., in an Apache configuration file
188 or in a .htaccess file). In particular, when rewriting URIs to add the
189 name of the Blosxom CGI script (e.g., "/cgi-bin/blosxom.cgi") you need
190 to ensure that such rules preserve any trailing slash on the end of
191 the URI and pass it on to Blosxom.
192
193 =head1 SEE ALSO
194
195 Blosxom Home/Docs/Licensing: http://www.blosxom.com/
196
197 Blosxom Plugin Docs: http://www.blosxom.com/documentation/users/plugins.html
198
199 =head1 BUGS
200
201 Address other bug reports and comments to the Blosxom mailing list:
202 http://www.yahoogroups.com/group/blosxom
203
204 =head1 LICENSE
205
206 slashredir Blosxom plugin Copyright 2004 Frank Hecker
207
208 Permission is hereby granted, free of charge, to any person obtaining a
209 copy of this software and associated documentation files (the "Software"),
210 to deal in the Software without restriction, including without limitation
211 the rights to use, copy, modify, merge, publish, distribute, sublicense,
212 and/or sell copies of the Software, and to permit persons to whom the
213 Software is furnished to do so, subject to the following conditions:
214
215 The above copyright notice and this permission notice shall be included
216 in all copies or substantial portions of the Software.
217
218 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
219 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
220 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
221 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
222 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
223 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
224 OTHER DEALINGS IN THE SOFTWARE.