1 // Copyright 2004-2008 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
113 get { return MonoRailConfiguration.GetConfig().MatchHostNameAndPath; }
116 private static bool ExcludeAppPath
118 get { return MonoRailConfiguration.GetConfig().ExcludeAppPath; }
121 private static string GetHostNameAndPath()
123 HttpContext context
= HttpContext
.Current
;
124 HttpRequest request
= context
.Request
;
126 String host
= request
.Headers
["host"];
128 if (String
.IsNullOrEmpty(host
))
130 return request
.FilePath
;
134 return host
+ request
.FilePath
;
138 private static string GetPathWithoutAppPath()
140 //if ApplicationPath.Length == 1 then it must be "/" which we don't want to remove
142 string appPath
= HttpContext
.Current
.Request
.ApplicationPath
;
143 string filePath
= HttpContext
.Current
.Request
.FilePath
;
145 return (appPath
.Length
== 1) ? filePath
: filePath
.Remove(0, appPath
.Length
);
148 private static string GetPath()
150 return HttpContext
.Current
.Request
.FilePath
;
153 private bool FindMatchAndReplace(String currentPath
, out String newPath
)
155 newPath
= String
.Empty
;
157 foreach(RoutingRule rule
in routingRules
)
159 if (rule
.CompiledRule
.IsMatch(currentPath
))
161 newPath
= rule
.CompiledRule
.Replace(currentPath
, rule
.Replace
);
163 //Append the query string
164 String queryString
= HttpContext
.Current
.Request
.Url
.Query
;
166 if (queryString
.Length
> 0)
168 //If we already have some query string params on the new path...
169 bool hasParams
= (newPath
.LastIndexOf("?") != -1);
173 //...make sure we append the query string nicely rather than adding another ?
174 queryString
= queryString
.Replace("?", "&");
177 newPath
+= queryString
;
182 string appPath
= HttpContext
.Current
.Request
.ApplicationPath
;
184 if (appPath
.Length
> 1)
186 newPath
= appPath
+ newPath
;
198 /// Returns the original path
199 /// (before rewriting occured), or <c>null</c>
200 /// if rewriting didn't occur on this request.
202 public static String OriginalPath
206 HttpContext context
= HttpContext
.Current
;
208 if (context
.Items
.Contains(OriginalPathKey
))
210 return context
.Items
[OriginalPathKey
] as String
;
217 private static void SaveOriginalPath(HttpContext context
, String virtualPath
)
219 context
.Items
.Add(OriginalPathKey
, virtualPath
);