2008-05-19 George Giolfan <georgegiolfan@yahoo.com>
[mono.git] / mcs / class / System.Web / System.Web.Configuration / HandlerFactoryConfiguration.cs
1 //
2 // System.Web.Configuration.HandlerFactoryConfiguration.cs
3 //  
4 //
5 // Authors:
6 //      Miguel de Icaza (miguel@novell.com)
7 //      Gonzalo Paniagua Javier (gonzalo@novell.com)
8 //
9 // (C) 2005 Novell, Inc (http://www.novell.com)
10 //
11
12 //
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:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
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.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Web.Util;
36 using System.Text.RegularExpressions;
37
38 namespace System.Web.Configuration {    
39         class HttpHandler {
40                 // If `null', we are the "*" match
41                 public string OriginalVerb;
42                 public string OriginalPath;
43                 
44                 public string [] Verbs;
45                 public FileMatchingInfo [] files;
46
47                 // To support lazy loading we keep the name around.
48                 public string TypeName;
49                 Type type;
50
51                 object instance;
52                 
53                 public HttpHandler (string verb, string path, string typename, Type t)
54                 {
55                         OriginalVerb = verb;
56                         OriginalPath = path;
57                         
58                         if (verb != "*")
59                                 Verbs = verb.Split (',');
60                         
61                         this.TypeName = typename;
62                         type = t;
63                 }
64
65                 //
66                 // Loads the a type by name and verifies that it implements
67                 // IHttpHandler or IHttpHandlerFactory
68                 //
69                 public static Type LoadType (string type_name)
70                 {
71                         Type t;
72                         
73                         try {
74                                 t = HttpApplication.LoadType (type_name, true);
75                         } catch {
76                                 throw new HttpException (String.Format ("Failed to load httpHandler type `{0}'", type_name));
77                         }
78
79                         if (typeof (IHttpHandler).IsAssignableFrom (t) ||
80                             typeof (IHttpHandlerFactory).IsAssignableFrom (t))
81                                 return t;
82                         
83                         throw new HttpException (String.Format ("Type {0} does not implement IHttpHandler or IHttpHandlerFactory", type_name));
84                 }
85
86                 public bool PathMatches (string p)
87                 {
88                         string [] paths = OriginalPath.Split (',');
89                         files = new FileMatchingInfo [paths.Length];
90
91                         int i = 0;
92                         foreach (string s in paths)
93                                 files [i++] = new FileMatchingInfo (s);
94                         
95                         int slash = p.LastIndexOf ('/');
96                         string orig = p;
97                         if (slash != -1)
98                                 p = p.Substring (slash);
99
100                         for (int j = files.Length; j > 0; ){
101                                 j--;
102                                 FileMatchingInfo fm = files [j];
103
104                                 if (fm.MatchExact != null)
105                                         return fm.MatchExact.Length == orig.Length && StrUtils.EndsWith (orig, fm.MatchExact, true);
106                                         
107                                 if (fm.EndsWith != null)
108                                         return StrUtils.EndsWith (p, fm.EndsWith, true);
109
110                                 if (fm.MatchExpr == "*")
111                                         return true;
112
113                                 /* convert to regexp */
114                                 return fm.RegExp.IsMatch (orig);
115                         }
116                         return false;
117                 }
118
119                 // Loads the handler, possibly delay-loaded.
120                 public object GetHandlerInstance ()
121                 {
122                         IHttpHandler ihh = instance as IHttpHandler;
123                         
124                         if (instance == null || (ihh != null && !ihh.IsReusable)){
125                                 if (type == null)
126                                         type = LoadType (TypeName);
127
128                                 instance = Activator.CreateInstance (type);
129                         } 
130                         
131                         return instance;
132                 }
133         }
134         
135         class HandlerFactoryConfiguration {
136                 ArrayList handlers;
137                 //HandlerFactoryConfiguration parent;
138                 int parent_items;
139
140                 public HandlerFactoryConfiguration (HandlerFactoryConfiguration parent)
141                 {
142                         //this.parent = parent;
143                         
144                         if (parent != null) {
145                                 handlers = new ArrayList (parent.handlers);
146                                 parent_items = handlers.Count;
147                         } else {
148                                 handlers = new ArrayList ();
149                         }
150                 }
151
152                 public void Clear ()
153                 {
154                         HttpApplication.ClearHandlerCache ();
155                         handlers.Clear ();
156                 }
157
158                 public void Add (string verb, string path, string type_name, bool validate)
159                 {
160                         Type type;
161
162                         if (validate){
163                                 type = HttpHandler.LoadType (type_name);
164                                 if (type == null)
165                                         throw new HttpException (String.Format ("Can not load {0}", type_name));
166                         } else
167                                 type = null;
168
169                         HttpApplication.ClearHandlerCache ();
170                         handlers.Add (new HttpHandler (verb, path, type_name, type));
171                 }
172
173                 public bool Remove (string verb, string path)
174                 {
175                         for (int i = handlers.Count - 1; i >= 0; i--) {
176                                 HttpHandler handler = (HttpHandler) handlers [i];
177
178                                 if (verb == handler.OriginalVerb && path == handler.OriginalPath){
179                                         HttpApplication.ClearHandlerCache ();
180                                         handlers.RemoveAt (i);
181                                         return true;
182                                 }
183                         }
184
185                         return false;
186                 }
187
188                 public object LocateHandler (string verb, string filepath)
189                 {
190                         int start, end;
191                         int count = handlers.Count;
192                         for (int k = 0; k < 2; k++) {
193                                 // First iteration searches for the mapping in the items added to this
194                                 // instance. The second one searches through the parent items if any.
195                                 start = (k == 0) ? parent_items : 0;
196                                 end = (k == 0) ? count : parent_items;
197                                 for (int i = start; i < end; i++) {
198                                         HttpHandler handler = (HttpHandler) handlers [i];
199
200                                         if (handler.Verbs == null){
201                                                 if (handler.PathMatches (filepath))
202                                                         return handler.GetHandlerInstance ();
203                                                 continue;
204                                         }
205
206                                         string [] verbs = handler.Verbs;
207                                         for (int j = verbs.Length; j > 0; ){
208                                                 j--;
209                                                 if (verbs [j] != verb)
210                                                         continue;
211                                                 if (handler.PathMatches (filepath))
212                                                         return handler.GetHandlerInstance ();
213                                         }
214                                 }
215                         }
216
217                         return null;
218                 }
219         }
220 }
221