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
.Services
18 using System
.Collections
;
19 using System
.Collections
.Specialized
;
23 using Castle
.MonoRail
.Framework
.Configuration
;
24 using Castle
.MonoRail
.Framework
.Internal
;
27 /// Breaks the url into smaller pieces to find out
28 /// the requested controller, action and optionally the area.
30 /// It alsos checks for default urls which map a single resource to an area/controller/action
33 public class DefaultUrlTokenizer
: IUrlTokenizer
, IServiceEnabledComponent
35 private readonly IDictionary defaultUrl2CustomUrlInfo
= new HybridDictionary(true);
38 /// Adds the default rule mapping.
41 /// A defautl rule can associate something like a 'default.castle'
42 /// to a controller/action like 'Home/index.castle'
44 /// <param name="url">The URL.</param>
45 /// <param name="area">The area.</param>
46 /// <param name="controller">The controller.</param>
47 /// <param name="action">The action.</param>
48 public void AddDefaultRule(string url
, string area
, string controller
, string action
)
55 defaultUrl2CustomUrlInfo
[url
] = new UrlInfo(area
, controller
, action
);
58 #region IServiceEnabledComponent
61 /// Services the specified provider.
63 /// <param name="provider">The provider.</param>
64 public void Service(IServiceProvider provider
)
66 MonoRailConfiguration config
= (MonoRailConfiguration
) provider
.GetService(typeof(MonoRailConfiguration
));
68 foreach(DefaultUrl url
in config
.DefaultUrls
)
70 AddDefaultRule(url
.Url
, url
.Area
, url
.Controller
, url
.Action
);
79 /// Tokenizes the URL.
81 /// <param name="rawUrl">The raw URL.</param>
82 /// <param name="pathInfo">The path info.</param>
83 /// <param name="uri">The URI.</param>
84 /// <param name="isLocal">if set to <c>true</c> request is local.</param>
85 /// <param name="appVirtualDir">Virtual directory</param>
86 /// <returns></returns>
87 public UrlInfo
TokenizeUrl(string rawUrl
, string pathInfo
, Uri uri
, bool isLocal
, string appVirtualDir
)
89 if (rawUrl
== null || rawUrl
.Length
== 0)
91 throw new ArgumentNullException("rawUrl", "rawUrl cannot be null or empty");
94 string domain
= uri
.Host
;
95 string subdomain
= GetDomainToken(domain
, 0);
97 if (subdomain
.Length
< subdomain
.Length
)
99 // Strip the subdomain from the main domain name
100 domain
= domain
.Substring(subdomain
.Length
);
103 if (rawUrl
[0] == '/')
105 rawUrl
= rawUrl
.Substring(1);
108 // Strip the appVirtualDir from the Url
109 if (appVirtualDir
!= null && appVirtualDir
!= "")
111 appVirtualDir
= appVirtualDir
.ToLower(System
.Globalization
.CultureInfo
.InvariantCulture
).Substring(1);
113 if (!rawUrl
.StartsWith(appVirtualDir
, true, System
.Globalization
.CultureInfo
.InvariantCulture
))
116 throw new UrlTokenizerException("Url does not start with the virtual dir");
119 rawUrl
= rawUrl
.Substring(appVirtualDir
.Length
);
122 string area
, controller
, action
;
124 // Is the url a custom url?
125 UrlInfo custom
= (UrlInfo
) defaultUrl2CustomUrlInfo
[rawUrl
];
130 controller
= custom
.Controller
;
131 action
= custom
.Action
;
135 ExtractAreaControllerAction(rawUrl
, out area
, out controller
, out action
);
138 string extension
= GetExtension(rawUrl
);
140 return new UrlInfo(domain
, subdomain
, appVirtualDir
, uri
.Scheme
, uri
.Port
, rawUrl
, area
, controller
, action
, extension
, pathInfo
);
146 /// Extracts the area controller action.
148 /// <param name="rawUrl">The raw URL.</param>
149 /// <param name="area">The area.</param>
150 /// <param name="controller">The controller.</param>
151 /// <param name="action">The action.</param>
152 private void ExtractAreaControllerAction(string rawUrl
, out string area
, out string controller
, out string action
)
154 string[] parts
= rawUrl
.Split('/');
156 if (parts
.Length
< 2)
158 throw new UrlTokenizerException("Url smaller than 2 tokens");
161 action
= parts
[parts
.Length
- 1];
163 int fileNameIndex
= action
.IndexOf('.');
165 if (fileNameIndex
!= -1)
167 action
= action
.Substring(0, fileNameIndex
);
170 controller
= parts
[parts
.Length
- 2];
174 if (parts
.Length
- 3 == 0)
176 area
= parts
[parts
.Length
- 3];
178 else if (parts
.Length
- 3 > 0)
180 StringBuilder areaSB
= new StringBuilder();
182 for(int i
= 0; i
<= parts
.Length
- 3; i
++)
184 if (parts
[i
] != null && parts
[i
].Length
> 0)
186 areaSB
.Append(parts
[i
]).Append('/');
190 if (areaSB
.Length
> 0)
195 area
= areaSB
.ToString();
200 /// Gets the domain token.
202 /// <param name="domain">The domain.</param>
203 /// <param name="token">The token index.</param>
204 /// <returns></returns>
205 protected static string GetDomainToken(string domain
, int token
)
207 string[] parts
= domain
.Split('.');
209 if (token
< parts
.Length
)
218 /// Gets the extension of the requested urls page without the preceding period.
220 /// <param name="url">URL.</param>
221 /// <returns>The resource file extension on the url (without the period).</returns>
222 protected static string GetExtension(string url
)
224 string ext
= Path
.GetExtension(url
);
228 return ext
.Substring(1);