1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.MonoRail
.Framework
18 using System
.Collections
;
20 using Castle
.MonoRail
.Framework
.Configuration
;
23 /// Provides routing basic services in response to rules defined in
24 /// <see cref="MonoRailConfiguration.RoutingRules"/>.
26 /// This class delegates the resolving of the path that will be evaluated
27 /// to derivided classes.
30 public class RoutingModule
: IHttpModule
32 internal static readonly String OriginalPathKey
= "rails.original_path";
33 private IList routingRules
;
36 /// Initializes a module and prepares it to handle requests.
38 /// <param name="context">An <see cref="T:System.Web.HttpApplication"></see> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application</param>
39 public void Init(HttpApplication context
)
41 context
.BeginRequest
+= OnBeginRequest
;
43 routingRules
= MonoRailConfiguration
.GetConfig().RoutingRules
;
47 /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"></see>.
54 /// Called when [begin request].
56 /// <param name="sender">The sender.</param>
57 /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
58 private void OnBeginRequest(object sender
, EventArgs e
)
60 if (routingRules
.Count
== 0) return;
62 HttpContext context
= HttpContext
.Current
;
63 HttpRequest request
= context
.Request
;
67 String sourcePath
= GetSourcePath();
69 SaveOriginalPath(context
, sourcePath
);
71 if (FindMatchAndReplace(sourcePath
, out newPath
))
73 // Handle things differently depending on wheter we need
74 // to keep a query string or not
76 int queryStringIndex
= newPath
.IndexOf('?');
78 if (queryStringIndex
== -1)
80 context
.RewritePath(newPath
);
84 String path
= newPath
.Substring(0, queryStringIndex
);
85 String queryString
= newPath
.Substring(queryStringIndex
+ 1);
86 context
.RewritePath(path
, request
.PathInfo
, queryString
);
92 /// Gets the source path.
94 /// <returns></returns>
95 protected static string GetSourcePath()
97 if (ShouldUseHostAndPath
)
99 return GetHostNameAndPath();
101 else if (ExcludeAppPath
)
103 return GetPathWithoutAppPath();
111 private static bool ShouldUseHostAndPath
115 return MonoRailConfiguration
.GetConfig().MatchHostNameAndPath
;
119 private static bool ExcludeAppPath
123 return MonoRailConfiguration
.GetConfig().ExcludeAppPath
;
127 private static string GetHostNameAndPath()
129 HttpContext context
= HttpContext
.Current
;
130 HttpRequest request
= context
.Request
;
132 String host
= request
.Headers
["host"];
134 if (String
.IsNullOrEmpty(host
))
136 return request
.FilePath
;
140 return host
+ request
.FilePath
;
144 private static string GetPathWithoutAppPath()
146 //if ApplicationPath.Length == 1 then it must be "/" which we don't want to remove
148 string appPath
= HttpContext
.Current
.Request
.ApplicationPath
;
149 string filePath
= HttpContext
.Current
.Request
.FilePath
;
151 return (appPath
.Length
== 1) ? filePath
: filePath
.Remove(0, appPath
.Length
);
154 private static string GetPath()
156 return HttpContext
.Current
.Request
.FilePath
;
159 private bool FindMatchAndReplace(String currentPath
, out String newPath
)
161 newPath
= String
.Empty
;
163 foreach(RoutingRule rule
in routingRules
)
165 if (rule
.CompiledRule
.IsMatch(currentPath
))
167 newPath
= rule
.CompiledRule
.Replace(currentPath
, rule
.Replace
);
169 //Append the query string
170 String queryString
= HttpContext
.Current
.Request
.Url
.Query
;
172 if (queryString
.Length
> 0)
174 //If we already have some query string params on the new path...
175 bool hasParams
= (newPath
.LastIndexOf("?") != -1);
179 //...make sure we append the query string nicely rather than adding another ?
180 queryString
= queryString
.Replace("?", "&");
183 newPath
+= queryString
;
188 string appPath
= HttpContext
.Current
.Request
.ApplicationPath
;
190 if (appPath
.Length
> 1)
192 newPath
= appPath
+ newPath
;
204 /// Returns the original path
205 /// (before rewriting occured), or <c>null</c>
206 /// if rewriting didn't occur on this request.
208 public static String OriginalPath
212 HttpContext context
= HttpContext
.Current
;
214 if (context
.Items
.Contains(OriginalPathKey
))
216 return context
.Items
[OriginalPathKey
] as String
;
223 private static void SaveOriginalPath(HttpContext context
, String virtualPath
)
225 context
.Items
.Add(OriginalPathKey
, virtualPath
);