HandlerFactoryConfiguration.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. //
  2. // System.Web.Configuration.HandlerFactoryConfiguration.cs
  3. //
  4. //
  5. // Authors:
  6. // Miguel de Icaza ([email protected])
  7. // Gonzalo Paniagua Javier ([email protected])
  8. //
  9. // (C) 2005 Novell, Inc (http://www.novell.com)
  10. //
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System;
  32. using System.Collections;
  33. using System.Web.Util;
  34. using System.Text.RegularExpressions;
  35. namespace System.Web.Configuration {
  36. class FileMatchingInfo {
  37. public string MatchExact;
  38. public string MatchExpr;
  39. // If set, we can fast-path the patch with string.EndsWith (FMI.EndsWith)
  40. public string EndsWith;
  41. public Regex RegExp;
  42. public FileMatchingInfo (string s)
  43. {
  44. MatchExpr = s;
  45. if (s[0] == '*' && (s.IndexOf ('*', 1) == -1))
  46. EndsWith = s.Substring (1);
  47. if (s.IndexOf ('*') == -1)
  48. MatchExact = "/" + s;
  49. if (MatchExpr != "*") {
  50. string expr = MatchExpr.Replace(".", "\\.").Replace("?", "\\?").Replace("*", ".*");
  51. if (expr.Length > 0 && expr [0] =='/')
  52. expr = expr.Substring (1);
  53. expr += "\\z";
  54. RegExp = new Regex (expr);
  55. }
  56. }
  57. }
  58. class HttpHandler {
  59. // If `null', we are the "*" match
  60. public string OriginalVerb;
  61. public string OriginalPath;
  62. public string [] Verbs;
  63. public FileMatchingInfo [] files;
  64. // To support lazy loading we keep the name around.
  65. public string TypeName;
  66. Type type;
  67. object instance;
  68. public HttpHandler (string verb, string path, string typename, Type t)
  69. {
  70. OriginalVerb = verb;
  71. OriginalPath = path;
  72. if (verb != "*")
  73. Verbs = verb.Split (',');
  74. string [] paths = path.Split (',');
  75. files = new FileMatchingInfo [paths.Length];
  76. int i = 0;
  77. foreach (string s in paths)
  78. files [i++] = new FileMatchingInfo (s);
  79. this.TypeName = typename;
  80. type = t;
  81. }
  82. //
  83. // Loads the a type by name and verifies that it implements
  84. // IHttpHandler or IHttpHandlerFactory
  85. //
  86. public static Type LoadType (string type_name)
  87. {
  88. Type t;
  89. try {
  90. t = Type.GetType (type_name, true);
  91. } catch (Exception e) {
  92. throw new HttpException (String.Format ("Failed to load httpHandler type `{0}'", type_name));
  93. }
  94. if (typeof (IHttpHandler).IsAssignableFrom (t) ||
  95. typeof (IHttpHandlerFactory).IsAssignableFrom (t))
  96. return t;
  97. throw new HttpException (String.Format ("Type {0} does not implement IHttpHandler or IHttpHandlerFactory", type_name));
  98. }
  99. public bool PathMatches (string p)
  100. {
  101. int slash = p.LastIndexOf ('/');
  102. string orig = p;
  103. if (slash != -1)
  104. p = p.Substring (slash);
  105. for (int j = files.Length; j > 0; ){
  106. j--;
  107. FileMatchingInfo fm = files [j];
  108. if (fm.MatchExact != null)
  109. return fm.MatchExact.Length == p.Length && StrUtils.EndsWith (p, fm.MatchExact);
  110. if (fm.EndsWith != null)
  111. return StrUtils.EndsWith (p, fm.EndsWith);
  112. if (fm.MatchExpr == "*")
  113. return true;
  114. /* convert to regexp */
  115. return fm.RegExp.IsMatch (orig);
  116. }
  117. return false;
  118. }
  119. // Loads the handler, possibly delay-loaded.
  120. public object GetHandlerInstance ()
  121. {
  122. IHttpHandler ihh = instance as IHttpHandler;
  123. if (instance == null || (ihh != null && !ihh.IsReusable)){
  124. if (type == null)
  125. type = LoadType (TypeName);
  126. instance = Activator.CreateInstance (type);
  127. }
  128. return instance;
  129. }
  130. }
  131. class HandlerFactoryConfiguration {
  132. ArrayList handlers;
  133. HandlerFactoryConfiguration parent;
  134. int parent_items;
  135. public HandlerFactoryConfiguration (HandlerFactoryConfiguration parent)
  136. {
  137. this.parent = parent;
  138. if (parent != null) {
  139. handlers = new ArrayList (parent.handlers);
  140. parent_items = handlers.Count;
  141. } else {
  142. handlers = new ArrayList ();
  143. }
  144. }
  145. public void Clear ()
  146. {
  147. handlers.Clear ();
  148. }
  149. public void Add (string verb, string path, string type_name, bool validate)
  150. {
  151. Type type;
  152. if (validate){
  153. type = HttpHandler.LoadType (type_name);
  154. if (type == null)
  155. throw new HttpException (String.Format ("Can not load {0}", type_name));
  156. } else
  157. type = null;
  158. handlers.Add (new HttpHandler (verb, path, type_name, type));
  159. }
  160. public bool Remove (string verb, string path)
  161. {
  162. for (int i = handlers.Count - 1; i >= 0; i--) {
  163. HttpHandler handler = (HttpHandler) handlers [i];
  164. if (verb == handler.OriginalVerb && path == handler.OriginalPath){
  165. handlers.RemoveAt (i);
  166. return true;
  167. }
  168. }
  169. return false;
  170. }
  171. public object LocateHandler (string verb, string filepath)
  172. {
  173. int start, end;
  174. int count = handlers.Count;
  175. for (int k = 0; k < 2; k++) {
  176. // First iteration searches for the mapping in the items added to this
  177. // instance. The second one searches through the parent items if any.
  178. start = (k == 0) ? parent_items : 0;
  179. end = (k == 0) ? count : parent_items;
  180. for (int i = start; i < end; i++) {
  181. HttpHandler handler = (HttpHandler) handlers [i];
  182. if (handler.Verbs == null){
  183. if (handler.PathMatches (filepath))
  184. return handler.GetHandlerInstance ();
  185. continue;
  186. }
  187. string [] verbs = handler.Verbs;
  188. for (int j = verbs.Length; j > 0; ){
  189. j--;
  190. if (verbs [j] != verb)
  191. continue;
  192. if (handler.PathMatches (filepath))
  193. return handler.GetHandlerInstance ();
  194. }
  195. }
  196. }
  197. return null;
  198. }
  199. }
  200. }