2 // System.Web.Configuration.HttpHandlerAction
5 // Chris Toshok (toshok@ximian.com)
6 // Daniel Nauck (dna(at)mono-project(dot)de)
8 // (C) 2005 Novell, Inc (http://www.novell.com)
9 // (C) 2008 Daniel Nauck
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Collections.Generic;
38 using System.ComponentModel;
39 using System.Configuration;
40 using System.Reflection;
41 using System.Text.RegularExpressions;
43 using System.Web.Util;
45 namespace System.Web.Configuration
47 public sealed class HttpHandlerAction: ConfigurationElement
49 static ConfigurationPropertyCollection _properties;
50 static ConfigurationProperty pathProp;
51 static ConfigurationProperty typeProp;
52 static ConfigurationProperty validateProp;
53 static ConfigurationProperty verbProp;
55 static HttpHandlerAction ()
57 pathProp = new ConfigurationProperty ("path", typeof (string), null,
58 TypeDescriptor.GetConverter (typeof (string)),
59 PropertyHelper.NonEmptyStringValidator,
60 ConfigurationPropertyOptions.IsRequired | ConfigurationPropertyOptions.IsKey);
61 typeProp = new ConfigurationProperty ("type", typeof (string), null,
62 TypeDescriptor.GetConverter (typeof (string)),
63 PropertyHelper.NonEmptyStringValidator,
64 ConfigurationPropertyOptions.IsRequired);
65 validateProp = new ConfigurationProperty ("validate", typeof (bool), true);
66 verbProp = new ConfigurationProperty ("verb", typeof (string), null,
67 TypeDescriptor.GetConverter (typeof (string)),
68 PropertyHelper.NonEmptyStringValidator,
69 ConfigurationPropertyOptions.IsRequired | ConfigurationPropertyOptions.IsKey);
71 _properties = new ConfigurationPropertyCollection ();
72 _properties.Add (pathProp);
73 _properties.Add (typeProp);
74 _properties.Add (validateProp);
75 _properties.Add (verbProp);
78 internal HttpHandlerAction ()
81 public HttpHandlerAction (string path, string type, string verb)
82 : this (path, type, verb, true)
85 public HttpHandlerAction (string path, string type, string verb, bool validate)
93 [ConfigurationProperty ("path", Options = ConfigurationPropertyOptions.IsRequired | ConfigurationPropertyOptions.IsKey)]
94 // LAMESPEC: MS lists no validator here but provides one in Properties.
96 get { return (string) base[pathProp]; }
97 set { base[pathProp] = value; }
100 [ConfigurationProperty ("type", Options = ConfigurationPropertyOptions.IsRequired)]
101 // LAMESPEC: MS lists no validator here but provides one in Properties.
103 get { return (string) base[typeProp]; }
104 set { base[typeProp] = value; }
107 [ConfigurationProperty ("validate", DefaultValue = true)]
108 public bool Validate {
109 get { return (bool) base[validateProp]; }
110 set { base[validateProp] = value; }
113 [ConfigurationProperty ("verb", Options = ConfigurationPropertyOptions.IsRequired | ConfigurationPropertyOptions.IsKey)]
114 // LAMESPEC: MS lists no validator here but provides one in Properties.
116 get { return (string) base[verbProp]; }
117 set { base[verbProp] = value; }
120 protected override ConfigurationPropertyCollection Properties {
121 get { return _properties; }
124 #region CompatabilityCode
128 string cached_verb = null;
129 string[] cached_verbs;
130 Dictionary<string, bool> cachedMatches = new Dictionary<string, bool> ();
131 Object pathMatchesLock = new Object ();
133 string[] SplitVerbs ()
138 cached_verbs = Verb.Split (',');
143 internal string[] Verbs {
145 if (cached_verb != Verb) {
146 cached_verbs = SplitVerbs();
155 // Loads the a type by name and verifies that it implements
156 // IHttpHandler or IHttpHandlerFactory
158 internal static Type LoadType (string type_name)
162 t = HttpApplication.LoadType (type_name, false);
165 throw new HttpException (String.Format ("Failed to load httpHandler type `{0}'", type_name));
167 if (typeof (IHttpHandler).IsAssignableFrom (t) ||
168 typeof (IHttpHandlerFactory).IsAssignableFrom (t))
171 throw new HttpException (String.Format ("Type {0} does not implement IHttpHandler or IHttpHandlerFactory", type_name));
174 internal bool PathMatches (string pathToMatch)
176 if (cachedMatches.ContainsKey (pathToMatch))
177 return cachedMatches [pathToMatch];
179 lock (pathMatchesLock)
181 if (cachedMatches.ContainsKey (pathToMatch))
182 return cachedMatches [pathToMatch];
185 string[] handlerPaths = Path.Split (',');
186 int slash = pathToMatch.LastIndexOf ('/');
187 string origPathToMatch = pathToMatch;
189 pathToMatch = pathToMatch.Substring (slash);
191 foreach (string handlerPath in handlerPaths)
193 if (handlerPath == "*")
199 string matchExact = null;
200 string endsWith = null;
203 if (handlerPath.Length > 0)
205 if (handlerPath [0] == '*' && (handlerPath.IndexOf ('*', 1) == -1))
206 endsWith = handlerPath.Substring (1);
208 if (handlerPath.IndexOf ('*') == -1)
209 if (handlerPath [0] != '/')
211 HttpContext ctx = HttpContext.Current;
212 HttpRequest req = ctx != null ? ctx.Request : null;
213 string vpath = req != null ? req.BaseVirtualDir : HttpRuntime.AppDomainAppVirtualPath;
216 vpath = String.Empty;
218 matchExact = String.Concat (vpath, "/", handlerPath);
222 if (matchExact != null)
224 result = matchExact.Length == origPathToMatch.Length && StrUtils.EndsWith (origPathToMatch, matchExact, true);
230 else if (endsWith != null)
232 result = StrUtils.EndsWith (pathToMatch, endsWith, true);
239 if (handlerPath != "*")
241 string expr = handlerPath.Replace (".", "\\.").Replace ("?", "\\?").Replace ("*", ".*");
242 if (expr.Length > 0 && expr [0] == '/')
243 expr = expr.Substring (1);
246 regEx = new Regex (expr, RegexOptions.IgnoreCase);
248 if (regEx.IsMatch (origPathToMatch))
256 if (!cachedMatches.ContainsKey (origPathToMatch))
257 cachedMatches.Add (origPathToMatch, result);
263 // Loads the handler, possibly delay-loaded.
264 internal object GetHandlerInstance ()
266 IHttpHandler ihh = instance as IHttpHandler;
268 if (instance == null || (ihh != null && !ihh.IsReusable)){
270 type = LoadType (Type);
272 instance = Activator.CreateInstance (type);