Index: lib/Jifty/Web.pm
===================================================================
--- lib/Jifty/Web.pm	(revision 5171)
+++ lib/Jifty/Web.pm	(working copy)
@@ -121,12 +121,18 @@
 the configuration file.  Takes an optional named path which will
 form the path part of the resulting URL.
 
+If the provided path appears to be a relative path, it is assumed to
+be relative to the application's base path, set by the C<BaseURL>
+configuration.  Passing a true value for C<absolute> makes it absolute
+to the server's root, instead of the application's root.
+
 =cut
 
 sub url {
     my $self = shift;
     my %args = (scheme => undef,
                 path => undef,
+                absolute => undef,
                 @_);
 
     my $uri;
@@ -171,6 +177,9 @@
 
     if (defined $args{path}) {
       my $path = $args{path};
+      # Add / in case we have an application path to tak on before
+      $path =~ s{^/?}{/};
+      $path = URI->new(Jifty->config->framework('Web')->{BaseURL})->path . $path unless $args{absolute};
       # strip off leading '/' because ->canonical provides one
       $path =~ s{^/}{};
       $uri->path_query($path);
@@ -628,9 +637,11 @@
 
     return ( 1 ) if $self->force_redirect;
 
+    my $current_path = URI->new(Jifty->config->framework('Web')->{BaseURL})->path . $self->request->path;
+
     if (!$self->request->is_subrequest
         and $self->next_page
-        and ( ( $self->next_page ne $self->request->path )
+        and ( ( $self->next_page ne $current_path )
               or $self->request->state_variables
               or $self->state_variables )
        )
@@ -674,24 +685,38 @@
 If you want to redirect to a page with parameters, pass in a
 L<Jifty::Web::Form::Clickable> object.
 
+If the URL to redirect to includes an explicit host, B<no continuation
+is saved>, and a simple redirect is done instead.
+
 =cut
 
 sub redirect {
     my $self = shift;
-    my $redir_to = shift || $self->next_page || $self->request->path;
+    my $redir_to = shift;
+    $self->log->debug("App root is ".URI->new(Jifty->config->framework('Web')->{BaseURL})->path);
+    $redir_to = URI->new(Jifty->config->framework('Web')->{BaseURL})->path . $redir_to if $redir_to and not ref $redir_to;
 
-    
+    $redir_to ||= $self->next_page;
+    $redir_to ||= URI->new(Jifty->config->framework('Web')->{BaseURL})->path . $self->request->path;
+
     my $page;
-
     if ( ref $redir_to and $redir_to->isa("Jifty::Web::Form::Clickable")) {
         $page = $redir_to;
     } else {
 
         $page = Jifty::Web::Form::Clickable->new();
-        #We set this after creation to ensure that plugins that massage clickables don't impact us
+        #We set this after creation to ensure that plugins that
+        #massage clickables don't impact us.  Also, the url is thus
+        #from the server root, not the application root
         $page->url($redir_to );
     }
 
+    # External redirect if it includes a host
+    if (URI->new($page->complete_url,"http")->host) {
+        return $self->_redirect($page->complete_url);
+    }
+
+
     carp "Don't include GET parameters in the redirect URL -- use a Jifty::Web::Form::Clickable instead.  See L<Jifty::Web/redirect>" if $page->url =~ /\?/;
 
     my %overrides = ( @_ );
@@ -732,8 +757,14 @@
         }
         my %parameters = ($page->parameters);
         $request->argument($_ => $parameters{$_}) for keys %parameters;
-        $request->path($page->url);
 
+        # We need to be careful that this path is relative to the
+        # application root, not the server root
+        my $app_root = URI->new(Jifty->config->framework('Web')->{BaseURL})->path;
+        my $url = $page->url;
+        $url =~ s/^$app_root//;
+        $request->path($url);
+
         $request->continuation($self->request->continuation);
         my $cont = Jifty::Continuation->new(
             request  => $request,
@@ -1084,8 +1115,10 @@
     # is returned.
     defined $self->call_trigger( 'include_css', @_ ) or return '';
 
+    my $base = URI->new(Jifty->config->framework('Web')->{BaseURL})->path;
+
     $self->out( '<link rel="stylesheet" type="text/css" '
-            . 'href="/static/css/main.css" />' );
+                . qq{href="$base/static/css/main.css" />} );
 
     return '';
 }
Index: lib/Jifty/Action/Redirect.pm
===================================================================
--- lib/Jifty/Action/Redirect.pm	(revision 5171)
+++ lib/Jifty/Action/Redirect.pm	(working copy)
@@ -45,13 +45,21 @@
 
 =head2 arguments
 
-The only argument to redirect is the C<url> to redirect to.
+The main argument is the C<url> to redirect to.
 
+If the C<url> appears to be a relative path, it is assumed to be
+relative to the application's base path, set by the C<BaseURL>
+configuration.  Passing a true value for the C<absolute>argument makes
+it absolute to the server's root.  Relative paths, and paths which
+contain a full URL, including scheme, are never modified, regardless
+of this option.
+
 =cut
 
 sub arguments {
     {
         url => { constructor => 1 },
+        absolute => {},
     }
 }
 
@@ -75,6 +83,9 @@
 
     # Find the URL to redirect to
     my $page = $self->argument_value('url');
+    if ($page =~ m|^/| and not $self->argument_value('absolute')) {
+        $page = URI->new(Jifty->config->framework('Web')->{BaseURL})->path . $page;
+    }
 
     # Set the next page and force the redirect
     Jifty->web->next_page($page);
Index: lib/Jifty/Continuation.pm
===================================================================
--- lib/Jifty/Continuation.pm	(revision 5171)
+++ lib/Jifty/Continuation.pm	(working copy)
@@ -143,10 +143,12 @@
 sub return_path_matches {
     my $self = shift;
     my $called_uri = $ENV{'REQUEST_URI'};
-    my $request_path = $self->request->path;
 
+    # Since REQUEST_URI is relative to the HTTP root, we need to make
+    # our internal request path relative to that, too.
+    my $request_path = URI->new(Jifty->config->framework('Web')->{BaseURL})->path . $self->request->path;
+
     # XXX TODO: WE should be using URI canonicalization
-
     my $escape;
     $called_uri =~ s{/+}{/}g;
     $called_uri = Encode::encode_utf8($called_uri);
@@ -213,7 +215,8 @@
         if defined $next->parent;
 
     # Redirect to right page if we're not there already
-    Jifty->web->_redirect($next->request->path . "?J:RETURN=" . $next->id);
+    my $page = URI->new(Jifty->config->framework('Web')->{BaseURL})->path . $next->request->path;
+    Jifty->web->_redirect($page . "?J:RETURN=" . $next->id);
     return 1;
 }
 
Index: lib/Jifty/Plugin/CompressedCSSandJS.pm
===================================================================
--- lib/Jifty/Plugin/CompressedCSSandJS.pm	(revision 5171)
+++ lib/Jifty/Plugin/CompressedCSSandJS.pm	(working copy)
@@ -62,7 +62,7 @@
     $self->gzip_enabled( exists $opt{gzip} ? $opt{gzip} : 1);
     $self->js( $opt{js} );
     $self->jsmin( $opt{jsmin} );
-    $self->cdn( $opt{cdn} || '');
+    $self->cdn( $opt{cdn} || URI->new(Jifty->config->framework('Web')->{BaseURL})->path);
 
     Jifty::Web->add_trigger(
         name      => 'include_javascript',
Index: lib/Jifty/Dispatcher.pm
===================================================================
--- lib/Jifty/Dispatcher.pm	(revision 5171)
+++ lib/Jifty/Dispatcher.pm	(working copy)
@@ -1230,7 +1230,8 @@
         );
 
         # Redirect with a continuation
-        Jifty->web->_redirect( "/__jifty/error/mason_internal_error?J:C=" . $c->id );
+        my $base = URI->new(Jifty->config->framework('Web')->{BaseURL})->path;
+        Jifty->web->_redirect( "$base/__jifty/error/mason_internal_error?J:C=" . $c->id );
     } elsif ($err) {
         die $err;
     }
Index: lib/Jifty/Request.pm
===================================================================
--- lib/Jifty/Request.pm	(revision 5171)
+++ lib/Jifty/Request.pm	(working copy)
@@ -571,8 +571,10 @@
     );
 
     # Set us up with the new continuation
+    my $base = URI->new(Jifty->config->framework('Web')->{BaseURL})->path;
     Jifty->web->_redirect( 
-                        $path
+                        $base
+                      . $path
                       . ( $path =~ /\?/ ? "&" : "?" ) . "J:C="
                       . $c->id );
 }
Index: lib/Jifty/Web/Form/Clickable.pm
===================================================================
--- lib/Jifty/Web/Form/Clickable.pm	(revision 5171)
+++ lib/Jifty/Web/Form/Clickable.pm	(working copy)
@@ -138,6 +138,14 @@
 
 For things that start off as links, give them an html C<target> attribute.
 
+=item absolute
+
+If the path appears to be a relative path, it is assumed to be
+relative to the application's base path, set by the C<BaseURL>
+configuration.  Passing a true value for C<absolute> makes it absolute
+to the server's root.  Relative paths, and paths which contain a full
+URL, including scheme, are never modified, regardless of this option.
+
 =cut
 
 =item Anything from L<Jifty::Web::Form::Element>
@@ -164,6 +172,10 @@
 
     $class->call_trigger( 'before_new', \%args );
 
+    if (defined $args{url} and $args{url} =~ m|^/| and not $args{absolute}) {
+        $args{url} = URI->new(Jifty->config->framework('Web')->{BaseURL})->path . $args{url};
+    }
+
     $args{render_as_button} = delete $args{as_button};
     $args{render_as_link}   = delete $args{as_link};
 
@@ -397,6 +409,7 @@
         $parameters{"J:CREATE"} = 1;
         $parameters{"J:PATH"}   = Jifty::Web::Form::Clickable->new(
             url          => $self->url,
+            absolute     => 1,
             parameters   => $self->{parameters},
             continuation => undef,
         )->complete_url;
@@ -439,9 +452,10 @@
     if ( $self->url ne $root and not $self->returns ) {
         Jifty::Util->require('Jifty::Action::Redirect');
         my $redirect = Jifty::Action::Redirect->new(
-            arguments => { url => $self->url } );
+            arguments => { url => $self->url }, absolute => 1 );
         $parameters{ $redirect->register_name } = ref $redirect;
         $parameters{ $redirect->form_field_name('url') } = $self->url;
+        $parameters{ $redirect->form_field_name('absolute') } = 1;
         $parameters{"J:ACTIONS"}
             = join( '!', @{ $self->submit }, $redirect->moniker )
             if $self->submit;
Index: lib/Jifty/Web/Form.pm
===================================================================
--- lib/Jifty/Web/Form.pm	(revision 5171)
+++ lib/Jifty/Web/Form.pm	(working copy)
@@ -36,6 +36,18 @@
 Disable B<browser> autocomplete for this form.  Jifty autocomplete will still
 work.
 
+=item submit_to
+
+Sets the URL that the form submits to, by default.
+
+=item absolute
+
+If the C<submit_to> appears to be a relative path, it is assumed to be
+relative to the application's base path, set by the C<BaseURL>
+configuration.  Passing a true value for C<absolute> makes it absolute
+to the server's root.  Relative paths, and paths which contain a full
+URL, including scheme, are never modified, regardless of this option.
+
 =back
 
 =cut
@@ -50,6 +62,7 @@
         submit_to => undef,
         target => undef,
         disable_autocomplete => undef,
+        absolute => undef,
         @_,
     );
 
@@ -83,8 +96,13 @@
                 target => undef,
                 submit_to => undef,
                 disable_autocomplete => undef,
+                absolute => undef,
                 @_);
 
+    if (defined $args{'submit_to'} and $args{'submit_to'} =~ m|^/| and not $args{absolute}) {
+        $args{'submit_to'} = URI->new(Jifty->config->framework('Web')->{BaseURL})->path . $args{'submit_to'};
+    }
+
     $self->actions( {} ) ;
     $self->printed_actions( {} ) ;
     $self->name($args{name});
@@ -199,7 +217,10 @@
         }
     }
 
-    my $form_start = qq!<form method="post" action="!  . Jifty->web->escape( $self->submit_to || $ENV{PATH_INFO}) . qq!"!;
+    my $submit_to = $self->submit_to;
+    $submit_to ||= URI->new(Jifty->config->framework('Web')->{BaseURL})->path . $ENV{PATH_INFO};
+
+    my $form_start = qq!<form method="post" action="!  . Jifty->web->escape( $submit_to ) . qq!"!;
     $form_start .= qq! name="@{[ $self->name ]}"! if defined $self->name;
     $form_start .= qq! target="@{[ $self->target ]}"! if defined $self->target;
     $form_start .= qq! autocomplete="off"!  if defined $self->disable_autocomplete;
