Minor changes to improve testability of helpers
[castle.git] / MonoRail / Castle.MonoRail.Framework / RoutingModule.cs
blobe366950490a5ce2256c7b48aa893eb6eee996a87
1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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
17 using System;
18 using System.Collections;
19 using System.Web;
20 using Castle.MonoRail.Framework.Configuration;
22 /// <summary>
23 /// Provides routing basic services in response to rules defined in
24 /// <see cref="MonoRailConfiguration.RoutingRules"/>.
25 /// <remarks>
26 /// This class delegates the resolving of the path that will be evaluated
27 /// to derivided classes.
28 /// </remarks>
29 /// </summary>
30 public class RoutingModule : IHttpModule
32 internal static readonly String OriginalPathKey = "rails.original_path";
33 private IList routingRules;
35 /// <summary>
36 /// Initializes a module and prepares it to handle requests.
37 /// </summary>
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;
46 /// <summary>
47 /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"></see>.
48 /// </summary>
49 public void Dispose()
53 /// <summary>
54 /// Called when [begin request].
55 /// </summary>
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;
65 String newPath;
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);
82 else
84 String path = newPath.Substring(0, queryStringIndex);
85 String queryString = newPath.Substring(queryStringIndex + 1);
86 context.RewritePath(path, request.PathInfo, queryString);
91 /// <summary>
92 /// Gets the source path.
93 /// </summary>
94 /// <returns></returns>
95 protected static string GetSourcePath()
97 if (ShouldUseHostAndPath)
99 return GetHostNameAndPath();
101 else if (ExcludeAppPath)
103 return GetPathWithoutAppPath();
105 else
107 return GetPath();
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;
138 else
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);
177 if (hasParams)
179 //...make sure we append the query string nicely rather than adding another ?
180 queryString = queryString.Replace("?", "&");
183 newPath += queryString;
186 if (ExcludeAppPath)
188 string appPath = HttpContext.Current.Request.ApplicationPath;
190 if (appPath.Length > 1)
192 newPath = appPath + newPath;
196 return true;
200 return false;
203 /// <summary>
204 /// Returns the original path
205 /// (before rewriting occured), or <c>null</c>
206 /// if rewriting didn't occur on this request.
207 /// </summary>
208 public static String OriginalPath
212 HttpContext context = HttpContext.Current;
214 if (context.Items.Contains(OriginalPathKey))
216 return context.Items[OriginalPathKey] as String;
219 return null;
223 private static void SaveOriginalPath(HttpContext context, String virtualPath)
225 context.Items.Add(OriginalPathKey, virtualPath);