This project is read-only.

Rewrite to an external site

Oct 13, 2011 at 9:02 PM
Edited Oct 13, 2011 at 10:03 PM

I want to do a simple external redirect.
When the user requests: http://localhost/orchard/survey I want to redirect them to: http://www.example.com/bar.html


I have the following rule set up:
Redirect /survey http://www.example.com/bar.html


Rather than redirecting to "http://www.example.com/bar.html", i get redirected to "http://localhost/orchardhttp:/www.example.com/bar.html"

The Request and Response I get are:


Request URL:http://localhost/orchard/survey

Request Method:GET

Status Code:302 Found

Request Headers:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3

Accept-Encoding:gzip,deflate,sdch

Accept-Language:en-US,en;q=0.8

Cache-Control:max-age=0

Connection:keep-alive

Cookie:Orchrd-orchard-=%7B%22Exp-N42-Settings%22%3A%22open%22%2C%22Exp-N42-Chapters%22%3A%22open%22%7D; __RequestVerificationToken_L29yY2hhcmQ_=2HxqDHQnaeElasHLDAceiqBziKbY84aNHQ8OSc5fNaPoHh/clLGwRltzValJ+YDwKepi4HKKAD3Vnn+SjNguq/uMZAjqDlP+vz4av95BKA9C0H5Tyb38hU47kVfJdp9ZbICwy+dH3abMcRgY0OfQBAiccK/p107W8qWYUIxIoAY=; .ASPXAUTH=32E879EED104451865FD890BAEE238DBE71829062796083DA883D36B1BA69563AC073358B7F253E6B91CD24DA26E8075F9633E855AE68194A014820EB5EC7C0564E6B947560CA1456F7B22D6D297D8CDA9C6E946F5EF5B3C43E13FB9A363C384572BFE04080AA4B2E1205F6F95E5462EECCEFB22E8BBCD28E2C483AD758C2EA08FF6D755CBF781DF81DA7D2833E882F6; ASP.NET_SessionId=4luxjoatkl3w3zfcuyi5i32y

Host:localhost

User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1

Response Headers:

Cache-Control:private

Content-Length:163

Content-Type:text/html; charset=utf-8

Date:Thu, 13 Oct 2011 20:54:18 GMT

Location:/orchardhttp:/www.example.com/bar.html

Server:Microsoft-IIS/7.5

X-AspNet-Version:4.0.30319

X-AspNetMvc-Version:3.0

X-Powered-By:ASP.NET

 

 


Notice that the Location header in the response is not correct.

Oct 13, 2011 at 10:44 PM

In RulesInterpreter.cs, if the command is "Redirect", you need to test if the "to" string is a fully qualified URL. If it is, you redirect to the full URL and don't do the Regex.Replace. I changed the source as follows and it seems to work.

RulesInterpreter.cs - Line 266:

 

to = MakeAbsolute(request, to);
from = MakeAbsolute(request, from);

try {
    if (Regex.IsMatch(url, from)) {
        if(Uri.IsWellFormedUriString(to, UriKind.Absolute)) 
        {
            url = to;
        }
        else
        {

            url = Regex.Replace(url, from, to);
        }
        // prevent infinite loops
        if (String.Equals(line, request.Url.ToString())) {
            return result;
        }
                           
        result = new RedirectResult(url);
    }
}


 

I think a similar change would be needed when RewriteRule is used instead of Redirect.

Oct 15, 2011 at 12:14 AM

Could you give me a repro case, I don’t see what you mean.

Also I can’t find examples for Redirect anymore on the docs. Maybe it has been deprecated in favor of Rewrite. But anyway I’d like an example. I tried with http:// and it worked fine.

Oct 17, 2011 at 4:10 PM

Well, Redirect may be a mod_alias directive, not mod_rewrite. But, Contrib.RewriteRules.Services.RulesInterpreter in the method Interpret explicitly checks for it at line 260 with if (line.StartsWith("Redirect"))

http://httpd.apache.org/docs/current/mod/mod_rewrite.html refers to other mod_rewrite documnentation which includes http://httpd.apache.org/docs/current/rewrite/remapping.html. This document refers to Redirect but never mentions that it is not part of mod_rewrite. So, I assumed it was.
Either way, it looks like Contrib.RewriteRules intends to support the Redirect directive because it is in the code. 

Here is the crux of my situation.

Orchard is installed in a virtual directory called /orchard

I set up a single redirect rule as 

Redirect /survey http://www.example.com/bar.html

From a browser I go to http://localhost/orchard/survey and set a break point in Interpret.cs I see the following:

  • line "Redirect /survey http://www.example.com/bar.html" string
  • from "/survey" string
  • to "http://www.example.com/bar.html" string
  • url "/orchard/survey" string

The destination URL is calculated by:

  • url = Regex.Replace(url, from, to);

which results in:

  • /orchardhttp://www.example.com/bar.html


Notice, that the original url contains my virtual directory path, but the Regex.Replace just replaces the /survey target, so it changes "/orchard/survey" to "/orchard/http://www.example.com/bar.html", which is wrong. Since we are doing a redirect to an external location with a fully qualified URL, we need to remove the virtual directory from the url.

Oct 17, 2011 at 4:14 PM
Edited Oct 17, 2011 at 4:29 PM

Now, I'm confused on how this should work.

I was using the rule:

Redirect /survey http://www.example.com/bar.html

which matches, but creates the incorrect redirect I cited above.

The rule

Redirect /orchard/survey http://www.example.com/bar.html

works correctly.

Oct 17, 2011 at 6:05 PM

As everything Redirect does is also handled by RewriteRule, I would prefer to remove it, this would save me some maintenance work. Is it ok for you to user RewriteRule ?

Oct 17, 2011 at 6:26 PM

I just added a unit test with application paths, and it works fine using Rewrite Rule, the way you would expect it:

Redirect /survey http://www.example.com/bar.html

Oct 17, 2011 at 6:36 PM

Wait. Did your test use the RewriteRule directive or the Redirect directive? The rule you show above is using Redirect and that does not work for me when I'm running Orchard in a virtual directory.

 

I can make this work with RewriteRule, but it raises a different question for me. The truth is I stumbled on the Redirect directive because I could not get RewriteRule to work. Now I know the following rule works:

RewriteRule ^survey$ http://www.example.com/bar.htm [R]

But last week I couldn't figure this out. And here is what I think had me confused:

RulesInterpreter trims the leading '/' from the path before it attempts a match. Is this the correct behavior? the documentation at http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule and http://httpd.apache.org/docs/current/rewrite/remapping.html#movehomedirs are full of examples that include the leading '/' in the rules, so I never tried it without it. I think the correct rule should be:

RewriteRule ^/survey$ http://www.example.com/bar.htm [R]

but that doesn't work.