Moved chain building and validation from Mono.Security to System
[mono.git] / mcs / class / System.Web / System.Web.UI / TemplateControl.cs
1 //
2 // System.Web.UI.TemplateControl.cs
3 //
4 // Authors:
5 //   Duncan Mak  (duncan@ximian.com)
6 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 //
9 // (C) 2002 Ximian, Inc. (http://www.ximian.com)
10 // Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
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
32 using System.Collections;
33 using System.ComponentModel;
34 using System.Reflection;
35 using System.Security.Permissions;
36 using System.Web.Compilation;
37 using System.Web.Util;
38 using System.Xml;
39 using System.IO;
40 using System.Runtime.InteropServices;
41 using System.Text;
42
43 namespace System.Web.UI
44 {
45         // CAS
46         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48         public abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService
49         {
50                 static readonly Assembly _System_Web_Assembly = typeof (TemplateControl).Assembly;
51                 static object abortTransaction = new object ();
52                 static object commitTransaction = new object ();
53                 static object error = new object ();
54                 static string [] methodNames = { "Page_Init",
55                                                  "Page_PreInit",
56                                                  "Page_PreLoad",
57                                                  "Page_LoadComplete",
58                                                  "Page_PreRenderComplete",
59                                                  "Page_SaveStateComplete",
60                                                  "Page_InitComplete",
61                                                  "Page_Load",
62                                                  "Page_DataBind",
63                                                  "Page_PreRender",
64                                                  "Page_Disposed",
65                                                  "Page_Error",
66                                                  "Page_Unload",
67                                                  "Page_AbortTransaction",
68                                                  "Page_CommitTransaction"};
69
70                 const BindingFlags bflags = BindingFlags.Public |
71                                             BindingFlags.NonPublic |
72                                             BindingFlags.Instance;
73
74                 string _appRelativeVirtualPath;
75                 StringResourceData resource_data;
76                 
77                 #region Constructor
78                 protected TemplateControl ()
79                 {
80                         TemplateControl = this;
81                         Construct ();
82                 }
83
84                 #endregion
85
86                 #region Properties
87                 [EditorBrowsable (EditorBrowsableState.Never)]
88                 [Obsolete]
89                 protected virtual int AutoHandlers {
90                         get { return 0; }
91                         set { }
92                 }
93
94                 [EditorBrowsable (EditorBrowsableState.Never)]
95                 protected virtual bool SupportAutoEvents {
96                         get { return true; }
97                 }
98
99                 public string AppRelativeVirtualPath {
100                         get { return _appRelativeVirtualPath; }
101                         set { _appRelativeVirtualPath = value; }
102                 }
103
104                 #endregion
105
106                 #region Methods
107
108                 protected virtual void Construct ()
109                 {
110                 }
111
112                 protected LiteralControl CreateResourceBasedLiteralControl (int offset, int size, bool fAsciiOnly)
113                 {
114                         if (resource_data == null)
115                                 return null;
116
117                         if (offset > resource_data.MaxOffset - size)
118                                 throw new ArgumentOutOfRangeException ("size");
119
120                         IntPtr ptr = AddOffset (resource_data.Ptr, offset);
121                         return new ResourceBasedLiteralControl (ptr, size);
122                 }
123
124                 class EvtInfo {
125                         public MethodInfo method;
126                         public string methodName;
127                         public EventInfo evt;
128                         public bool noParams;
129                 }
130
131                 static Hashtable auto_event_info;
132                 static object auto_event_info_monitor = new Object ();
133
134                 internal void WireupAutomaticEvents ()
135                 {
136                         if (!SupportAutoEvents || !AutoEventWireup)
137                                 return;
138
139                         ArrayList events = null;
140
141                         /* Avoid expensive reflection operations by computing the event info only once */
142                         lock (auto_event_info_monitor) {
143                                 if (auto_event_info == null)
144                                         auto_event_info = new Hashtable ();
145                                 events = (ArrayList)auto_event_info [GetType ()];
146                                 if (events == null) {
147                                         events = CollectAutomaticEventInfo ();
148                                         auto_event_info [GetType ()] = events;
149                                 }
150                         }
151
152                         for (int i = 0; i < events.Count; ++i) {
153                                 EvtInfo evinfo = (EvtInfo)events [i];
154                                 if (evinfo.noParams) {
155                                         NoParamsInvoker npi = new NoParamsInvoker (this, evinfo.method);
156                                         evinfo.evt.AddEventHandler (this, npi.FakeDelegate);
157                                 } else
158                                         evinfo.evt.AddEventHandler (this, Delegate.CreateDelegate (typeof (EventHandler), this, evinfo.method));
159                         }
160                 }
161
162                 ArrayList CollectAutomaticEventInfo () {
163                         ArrayList events = new ArrayList ();
164
165                         foreach (string methodName in methodNames) {
166                                 MethodInfo method = null;
167                                 Type type;
168                                 for (type = GetType (); type.Assembly != _System_Web_Assembly; type = type.BaseType) {
169                                         method = type.GetMethod (methodName, bflags);
170                                         if (method != null)
171                                                 break;
172                                 }
173                                 if (method == null)
174                                         continue;
175
176                                 if (method.DeclaringType != type) {
177                                         if (!method.IsPublic && !method.IsFamilyOrAssembly &&
178                                             !method.IsFamilyAndAssembly && !method.IsFamily)
179                                                 continue;
180                                 }
181
182                                 if (method.ReturnType != typeof (void))
183                                         continue;
184
185                                 ParameterInfo [] parms = method.GetParameters ();
186                                 int length = parms.Length;
187                                 bool noParams = (length == 0);
188                                 if (!noParams && (length != 2 ||
189                                     parms [0].ParameterType != typeof (object) ||
190                                     parms [1].ParameterType != typeof (EventArgs)))
191                                     continue;
192
193                                 int pos = methodName.IndexOf ('_');
194                                 string eventName = methodName.Substring (pos + 1);
195                                 EventInfo evt = type.GetEvent (eventName);
196                                 if (evt == null) {
197                                         /* This should never happen */
198                                         continue;
199                                 }
200
201                                 EvtInfo evinfo = new EvtInfo ();
202                                 evinfo.method = method;
203                                 evinfo.methodName = methodName;
204                                 evinfo.evt = evt;
205                                 evinfo.noParams = noParams;
206
207                                 events.Add (evinfo);
208                         }
209
210                         return events;
211                 }
212
213                 [EditorBrowsable (EditorBrowsableState.Never)]
214                 protected virtual void FrameworkInitialize ()
215                 {
216                 }
217
218                 Type GetTypeFromControlPath (string virtualPath)
219                 {
220                         if (virtualPath == null)
221                                 throw new ArgumentNullException ("virtualPath");
222
223                         string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
224                         return BuildManager.GetCompiledType (vpath);
225                 }
226
227                 public Control LoadControl (string virtualPath)
228                 {
229                         if (virtualPath == null)
230                                 throw new ArgumentNullException ("virtualPath");
231                         Type type = GetTypeFromControlPath (virtualPath);
232                         
233                         return LoadControl (type, null);
234                 }
235
236                 public Control LoadControl (Type type, object[] parameters) 
237                 {
238                         object [] attrs = null;
239
240                         if (type != null)
241                                 type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
242                         if (attrs != null && attrs.Length == 1) {
243                                 PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
244                                 PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
245                                 ctrl.VaryByParams = attr.VaryByParams;
246                                 ctrl.VaryByControls = attr.VaryByControls;
247                                 ctrl.VaryByCustom = attr.VaryByCustom;
248                                 return ctrl;
249                         }
250
251                         object control = Activator.CreateInstance (type, parameters);
252                         if (control is UserControl)
253                                 ((UserControl) control).InitializeAsUserControl (Page);
254
255                         return (Control) control;
256                 }
257
258                 public ITemplate LoadTemplate (string virtualPath)
259                 {
260                         if (virtualPath == null)
261                                 throw new ArgumentNullException ("virtualPath");
262                         Type t = GetTypeFromControlPath (virtualPath);
263                         return new SimpleTemplate (t);
264                 }
265
266                 protected virtual void OnAbortTransaction (EventArgs e)
267                 {
268                         EventHandler eh = Events [abortTransaction] as EventHandler;
269                         if (eh != null)
270                                 eh (this, e);
271                 }
272
273                 protected virtual void OnCommitTransaction (EventArgs e)
274                 {
275                         EventHandler eh = Events [commitTransaction] as EventHandler;
276                         if (eh != null)
277                                 eh (this, e);
278                 }
279
280                 protected virtual void OnError (EventArgs e)
281                 {
282                         EventHandler eh = Events [error] as EventHandler;
283                         if (eh != null)
284                                 eh (this, e);
285                 }
286
287                 public Control ParseControl (string content)
288                 {
289                         if (content == null)
290                                 throw new ArgumentNullException ("content");
291
292                         // FIXME: This method needs to be rewritten in some sane way - the way it is now,
293                         // is a kludge. New version should not use
294                         // UserControlParser.GetCompiledType, but instead resort to some other way
295                         // of creating the content (template instantiation? BuildManager? TBD)
296                         TextReader reader = new StringReader (content);
297                         Type control = UserControlParser.GetCompiledType (reader, content.GetHashCode (), HttpContext.Current);
298                         if (control == null)
299                                 return null;
300
301                         TemplateControl parsedControl = Activator.CreateInstance (control, null) as TemplateControl;
302                         if (parsedControl == null)
303                                 return null;
304
305                         if (this is System.Web.UI.Page)
306                                 parsedControl.Page = (System.Web.UI.Page) this;
307                         parsedControl.FrameworkInitialize ();
308                         
309                         Control ret = new Control ();
310                         int count = parsedControl.Controls.Count;
311                         Control[] parsedControlControls = new Control [count];
312                         parsedControl.Controls.CopyTo (parsedControlControls, 0);
313
314                         for (int i = 0; i < count; i++)
315                                 ret.Controls.Add (parsedControlControls [i]);
316
317                         parsedControl = null;
318                         return ret;
319                 }
320
321                 [MonoTODO ("Parser filters not implemented yet. Calls ParseControl (string) for now.")]
322                 public Control ParseControl (string content, bool ignoreParserFilter)
323                 {
324                         return ParseControl (content);
325                 }
326         
327                 [EditorBrowsable (EditorBrowsableState.Never)]
328                 public object ReadStringResource ()
329                 {
330                         return ReadStringResource (GetType ());
331                 }
332
333                 class StringResourceData {
334                         public IntPtr Ptr;
335                         public int Length;
336                         public int MaxOffset;
337                 }
338
339                 protected object GetGlobalResourceObject (string className, string resourceKey)
340                 {
341                         return HttpContext.GetGlobalResourceObject (className, resourceKey);
342                 }
343
344                 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
345                 {
346                         if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) ||
347                             String.IsNullOrEmpty (className) || objType == null)
348                                 return null;
349
350                         object globalObject = GetGlobalResourceObject (className, resourceKey);
351                         if (globalObject == null)
352                                 return null;
353                         
354                         TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
355                         if (converter == null || !converter.CanConvertFrom (globalObject.GetType ()))
356                                 return null;
357                         
358                         return converter.ConvertFrom (globalObject);
359                 }
360
361                 protected object GetLocalResourceObject (string resourceKey)
362                 {
363                         return HttpContext.GetLocalResourceObject (VirtualPathUtility.ToAbsolute (this.AppRelativeVirtualPath),
364                                                                    resourceKey);
365                 }
366                 
367                 protected object GetLocalResourceObject (string resourceKey, Type objType, string propName)
368                 {
369                         if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) || objType == null)
370                                 return null;
371
372                         object localObject = GetLocalResourceObject (resourceKey);
373                         if (localObject == null)
374                                 return null;
375                         
376                         TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
377                         if (converter == null || !converter.CanConvertFrom (localObject.GetType ()))
378                                 return null;
379                         
380                         return converter.ConvertFrom (localObject);
381                 }
382
383                 internal override TemplateControl TemplateControlInternal {
384                         get { return this; }
385                 }
386                 
387                 [EditorBrowsable (EditorBrowsableState.Never)]
388                 public static object ReadStringResource (Type t)
389                 {
390                         StringResourceData data = new StringResourceData ();
391                         if (ICalls.GetUnmanagedResourcesPtr (t.Assembly, out data.Ptr, out data.Length))
392                                 return data;
393
394                         throw new HttpException ("Unable to load the string resources.");
395                 }
396
397                 [EditorBrowsable (EditorBrowsableState.Never)]
398                 protected void SetStringResourcePointer (object stringResourcePointer,
399                                                          int maxResourceOffset)
400                 {
401                         StringResourceData rd = stringResourcePointer as StringResourceData;
402                         if (rd == null)
403                                 return;
404
405                         if (maxResourceOffset < 0 || maxResourceOffset > rd.Length)
406                                 throw new ArgumentOutOfRangeException ("maxResourceOffset");
407
408                         resource_data = new StringResourceData ();
409                         resource_data.Ptr = rd.Ptr;
410                         resource_data.Length = rd.Length;
411                         resource_data.MaxOffset = maxResourceOffset > 0 ? Math.Min (maxResourceOffset, rd.Length) : rd.Length;
412                 }
413
414                 static IntPtr AddOffset (IntPtr ptr, int offset)
415                 {
416                         if (offset == 0)
417                                 return ptr;
418
419                         if (IntPtr.Size == 4) {
420                                 int p = ptr.ToInt32 () + offset;
421                                 ptr = new IntPtr (p);
422                         } else {
423                                 long p = ptr.ToInt64 () + offset;
424                                 ptr = new IntPtr (p);
425                         }
426                         return ptr;
427                 }
428
429                 [EditorBrowsable (EditorBrowsableState.Never)]
430                 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset, int size, bool fAsciiOnly)
431                 {
432                         if (resource_data == null)
433                                 return; // throw?
434                         if (output == null)
435                                 throw new ArgumentNullException ("output");
436                         if (offset > resource_data.MaxOffset - size)
437                                 throw new ArgumentOutOfRangeException ("size");
438
439                         //TODO: fAsciiOnly?
440                         IntPtr ptr = AddOffset (resource_data.Ptr, offset);
441                         HttpWriter writer = output.GetHttpWriter ();
442                         
443                         if (writer == null || writer.Response.ContentEncoding.CodePage != 65001) {
444                                 byte [] bytes = new byte [size];
445                                 Marshal.Copy (ptr, bytes, 0, size);
446                                 output.Write (Encoding.UTF8.GetString (bytes));
447                                 bytes = null;
448                                 return;
449                         }
450
451                         writer.WriteUTF8Ptr (ptr, size);
452                 }
453
454                 #endregion
455
456                 #region Events
457
458                 [WebSysDescription ("Raised when the user aborts a transaction.")]
459                 public event EventHandler AbortTransaction {
460                         add { Events.AddHandler (abortTransaction, value); }
461                         remove { Events.RemoveHandler (abortTransaction, value); }
462                 }
463
464                 [WebSysDescription ("Raised when the user initiates a transaction.")]
465                 public event EventHandler CommitTransaction {
466                         add { Events.AddHandler (commitTransaction, value); }
467                         remove { Events.RemoveHandler (commitTransaction, value); }
468                 }
469
470                 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
471                 public event EventHandler Error {
472                         add { Events.AddHandler (error, value); }
473                         remove { Events.RemoveHandler (error, value); }
474                 }
475
476                 #endregion
477
478                 class SimpleTemplate : ITemplate
479                 {
480                         Type type;
481
482                         public SimpleTemplate (Type type)
483                         {
484                                 this.type = type;
485                         }
486
487                         public void InstantiateIn (Control control)
488                         {
489                                 Control template = Activator.CreateInstance (type) as Control;
490                                 template.SetBindingContainer (false);
491                                 control.Controls.Add (template);
492                         }
493                 }
494
495                 protected internal object Eval (string expression)
496                 {
497                         return DataBinder.Eval (Page.GetDataItem(), expression);
498                 }
499         
500                 protected internal string Eval (string expression, string format)
501                 {
502                         return DataBinder.Eval (Page.GetDataItem(), expression, format);
503                 }
504         
505                 protected internal object XPath (string xpathexpression)
506                 {
507                         return XPathBinder.Eval (Page.GetDataItem(), xpathexpression);
508                 }
509         
510                 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
511                 {
512                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
513                 }
514
515                 protected internal string XPath (string xpathexpression, string format)
516                 {
517                         return XPathBinder.Eval (Page.GetDataItem(), xpathexpression, format);
518                 }
519         
520                 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
521                 {
522                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
523                 }
524
525                 protected internal IEnumerable XPathSelect (string xpathexpression)
526                 {
527                         return XPathBinder.Select (Page.GetDataItem(), xpathexpression);
528                 }
529
530                 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
531                 {
532                         return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
533                 }
534
535                 // IFilterResolutionService
536
537                 [MonoTODO ("Not implemented")]
538                 int IFilterResolutionService.CompareFilters (string filter1, string filter2)
539                 {
540                         throw new NotImplementedException ();
541                 }
542
543                 [MonoTODO ("Not implemented")]
544                 bool IFilterResolutionService.EvaluateFilter (string filterName)
545                 {
546                         throw new NotImplementedException ();
547                 }
548         }
549 }