Bug: Redirection from view to viewauth can fail if the RewriteEngine is used
The function
view in lib/TWiki/UI/View.pm assumes that REQUEST_URI contains "/view". If URIs are rewritten using Apache's RewriteEngine, this assumption is not necessarily true, resulting in a redirection endless loop.
Test case
Add a rewrite rule in Apache's httpd.conf file
RewriteEngine on
RewriteRule ^/main/(.*) /twiki/bin/view/Main/$1 [l,pt]
Using "http://127.0.0.1/main/WebHome" and other existing Topics works correctly as expected.
Whereas accessing "http://127.0.0.1/main/NotExistingTopic" will fail with an unlimited redirection browser error message.
The httpd access log file shows a series of redirections to the same URL (in the un-rewritten form).
If the rewrite logging is activated, it shows the correct URL rewriting from "/main/NotExistingTopic"
to "/twiki/bin/view/Main/NotExistingTopic". Thus the RewriteRule is applied correctly.
The problem lays in the hardcoded replacement of "/view" by "/viewauth" in the
view function in lib/TWiki/UI/View.pm
for non-existing topics.
For rewritten URLs the environment variable REQUEST_URI holds the original URL which does not contain "/view".
Thus the replacement leaves the URI unchanged. As a result the client's browser is redirected to the same
location over and over.
This can be fixed by testing for "/view" in REQUEST_URI.
A second bug exists in the original code if REQUEST_URI is empty. For this case the redirection is
constructed using SCRIPT_FILENAME which is prefixed by the $TWiki::scriptUrlPath.
SCRIPT_FILENAME is usually an
absolute path name of the
CGI script, thus the absolute part of the
path name (including the $TWiki::scriptUrlPath part) has to be deleted before the redirection URI
is constructed. Otherwise the browser will be redirected to something like
"http://127.0.0.1/twiki/bin//usr/local/httpd/twiki/bin/viewauth/Main/NotExistingTopic".
This can be fixed by stripping off the prefix before "/viewauth". In addition one can use the
environment variable SCRIPT_NAME containing the relative URL to the
CGI script instead if it exists.
Environment
--
BerndRaichle - 06 Aug 2004
Follow up
Here is a fix proposal.
Fix record
*** lib/TWiki/UI/View.pm_ORIG Sat Jul 10 10:15:22 2004
--- lib/TWiki/UI/View.pm Fri Aug 6 14:46:59 2004
***************
*** 257,266 ****
# instead of non authenticated view script
my $url = $ENV{"REQUEST_URI"};
! if( $url ) {
# $url i.e. is "twiki/bin/view.cgi/Web/Topic?cms1=val1&cmd2=val2"
$url =~ s|/view|/viewauth|o;
$url = "$TWiki::urlHost$url";
} else {
$url = "$TWiki::urlHost$TWiki::scriptUrlPath/$viewauthFile/$webName/$topic";
}
TWiki::UI::redirect( $url );
--- 257,277 ----
# instead of non authenticated view script
my $url = $ENV{"REQUEST_URI"};
! if( $url && $url =~ m|/view| ) {
# $url i.e. is "twiki/bin/view.cgi/Web/Topic?cms1=val1&cmd2=val2"
$url =~ s|/view|/viewauth|o;
$url = "$TWiki::urlHost$url";
} else {
+ # If REQUEST_URI is rewritten and does not contain the name "view"
+ # try looking at the CGI environment variable SCRIPT_NAME.
+ $url = $ENV{'SCRIPT_NAME'};
+ if ($url && $url =~ m|/view| ) {
+ $url =~ s|/view|/viewauth|o;
+ $url = "$TWiki::urlHost$url/$webName/$topic";
+ } else {
+ # If SCRIPT_NAME doesn not contain the name "view"
+ # the last hope is to try the SCRIPT_FILENAME ...
+ $viewauthFile =~ s|^.*/viewauth|/viewauth|o; # strip off $Twiki::scriptUrlPath
$url = "$TWiki::urlHost$TWiki::scriptUrlPath/$viewauthFile/$webName/$topic";
+ }
}
TWiki::UI::redirect( $url );
--
BerndRaichle - 06 Aug 2004
Fix commited to
SVN, thankyou very much for the patch! - sorry for the delay.
--
SvenDowideit - 22 Aug 2004
I have not tested this, but reading the code it looks like the spec changes and possibly introduces a new bug. Assuming the full URL path is
/rewritten/Web/Topic?cmd1=val1&cmd2=val2, it will go into the first
else part, then into the second
else where it builds the URL and throws away the extended path
cmd1=val1&cmd2=val2.
--
PeterThoeny - 22 Aug 2004
This is true. Btw., the second
else in the
original code has the same restriction (it is
now the third
else). But in the original code the else branch is only executed if
REQUEST_URI has no value, which doesn't happen if an httpd like Apache is used.
To fix this problem one can either
assemble the URL using
SCRIPT_NAME,
PATH_INFO, and
QUERY_STRING or
disassemble REQUEST_URI into the part before
$webName/$topic, and the part after it. Looking at the
CGI 1.1 standard,
SCRIPT_NAME,
PATH_INFO, and
QUERY_STRING are in the canonical list of request variables, whereas
REQUEST_URI is not. Thus I prefer to use the assembling approach.
Fix record (second try)
*** View.pm Fri Aug 6 14:46:59 2004
--- View.pm Mon Aug 23 16:45:14 2004
***************
*** 264,276 ****
# If REQUEST_URI is rewritten and does not contain the name "view"
# try looking at the CGI environment variable SCRIPT_NAME.
! $url = $ENV{'SCRIPT_NAME'};
! if ($url && $url =~ m|/view| ) {
! $url =~ s|/view|/viewauth|o;
! $url = "$TWiki::urlHost$url/$webName/$topic";
} else {
! # If SCRIPT_NAME doesn not contain the name "view"
# the last hope is to try the SCRIPT_FILENAME ...
$viewauthFile =~ s|^.*/viewauth|/viewauth|o; # strip off $Twiki::scriptUrlPath
! $url = "$TWiki::urlHost$TWiki::scriptUrlPath/$viewauthFile/$webName/$topic";
}
}
--- 264,284 ----
# If REQUEST_URI is rewritten and does not contain the name "view"
# try looking at the CGI environment variable SCRIPT_NAME.
! #
! # Assemble the new URL using the host, the changed script name,
! # the path info, and the query string. All three query variables
! # are in the list of the canonical request meta variables in CGI 1.1.
! my $script = $ENV{'SCRIPT_NAME'};
! my $pathInfo = $ENV{'PATH_INFO'};
! my $queryString = $ENV{'QUERY_STRING'};
! $pathInfo = '/' . $pathInfo if ($pathInfo);
! $queryString = '?' . $queryString if ($queryString);
! if ($script && $script =~ m|/view| ) {
! $script =~ s|/view|/viewauth|o;
! $url = "$TWiki::urlHost$script$pathInfo$queryString";
} else {
! # If SCRIPT_NAME does not contain the name "view"
# the last hope is to try the SCRIPT_FILENAME ...
$viewauthFile =~ s|^.*/viewauth|/viewauth|o; # strip off $Twiki::scriptUrlPath
! $url = "$TWiki::urlHost$TWiki::scriptUrlPath/$viewauthFile$pathInfo$queryString";
}
}
--
BerndRaichle - 23 Aug 2004