Merge pull request #2971 from BrzVlad/feature-cross-binprot
[mono.git] / mcs / class / referencesource / System.Web / Profile / ProfileModule.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="ProfileModule.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 /*
8  * ProfileModule class
9  *
10  * Copyright (c) 1999 Microsoft Corporation
11  */
12
13 namespace System.Web.Profile {
14     using System.Web;
15     using System.Text;
16     using System.Web.Compilation;
17     using System.Web.Configuration;
18     using System.Web.Caching;
19     using System.Collections;
20     using System.Web.Util;
21     using System.Security.Principal;
22     using System.Security.Permissions;
23     using System.Reflection;
24     using System.Web.Security;
25     using System.Globalization;
26     using System.Runtime.Serialization;
27     using System.Collections.Specialized;
28     using System.Runtime.Serialization.Formatters.Binary;
29     using System.IO;
30     using System.Xml.Serialization;
31     using System.ComponentModel;
32     using System.Configuration;
33 #if !FEATURE_PAL
34     using System.Web.DataAccess;
35 #endif // !FEATURE_PAL
36
37     /// <devdoc>
38     ///    <para>[To be supplied.]</para>
39     /// </devdoc>
40     public sealed class ProfileModule : IHttpModule
41     {
42         private static object                   s_Lock              = new object();
43         private ProfileEventHandler             _eventHandler       = null;
44
45         private ProfileMigrateEventHandler _MigrateEventHandler;
46         private ProfileAutoSaveEventHandler _AutoSaveEventHandler;
47
48         /// <devdoc>
49         ///    <para>
50         ///       Initializes a new instance of the <see cref='System.Web.Security.ProfileModule'/>
51         ///       class.
52         ///     </para>
53         /// </devdoc>
54         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
55         public ProfileModule()
56         {
57         }
58
59         /// <devdoc>
60         ///    This is a Global.asax event which must be
61         ///    named FormsAuthorize_OnAuthorize event. It's used by advanced users to
62         ///    customize cookie authentication.
63         /// </devdoc>
64         public event ProfileEventHandler Personalize
65         {
66             add { _eventHandler += value; }
67             remove { _eventHandler -= value; }
68         }
69
70         public event ProfileMigrateEventHandler MigrateAnonymous
71         {
72             add { _MigrateEventHandler += value; }
73             remove { _MigrateEventHandler -= value; }
74         }
75
76         public event ProfileAutoSaveEventHandler ProfileAutoSaving {
77             add { _AutoSaveEventHandler += value; }
78             remove { _AutoSaveEventHandler -= value; }
79         }
80
81         /// <devdoc>
82         ///    <para>[To be supplied.]</para>
83         /// </devdoc>
84         public void Dispose()
85         {
86         }
87
88         /// <devdoc>
89         ///    <para>[To be supplied.]</para>
90         /// </devdoc>
91         public void Init(HttpApplication app)
92         {
93             if (ProfileManager.Enabled) {
94                 app.AcquireRequestState += new EventHandler(this.OnEnter);
95                 if (ProfileManager.AutomaticSaveEnabled) {
96                     app.EndRequest += new EventHandler(this.OnLeave);
97                 }
98             }            
99         }
100
101         private void OnPersonalize(ProfileEventArgs e)
102         {
103             if (_eventHandler != null)
104                 _eventHandler(this, e);
105
106             if (e.Profile != null)
107             {
108                 e.Context._Profile = e.Profile;
109                 return;
110             }
111
112             e.Context._ProfileDelayLoad = true;
113         }
114
115         ////////////////////////////////////////////////////////////
116         ////////////////////////////////////////////////////////////
117         ////////////////////////////////////////////////////////////
118
119         /// <devdoc>
120         ///    <para>[To be supplied.]</para>
121         /// </devdoc>
122         private void OnEnter(Object source, EventArgs eventArgs)
123         {
124             HttpContext context = ((HttpApplication)source).Context;
125             OnPersonalize(new ProfileEventArgs(context));
126             if (context.Request.IsAuthenticated && !string.IsNullOrEmpty(context.Request.AnonymousID) && _MigrateEventHandler != null)
127             {
128                 ProfileMigrateEventArgs e = new ProfileMigrateEventArgs(context, context.Request.AnonymousID);
129                 _MigrateEventHandler(this, e);
130             }
131         }
132
133         private void OnLeave(Object source, EventArgs eventArgs)
134         {
135             HttpApplication app = (HttpApplication)source;
136             HttpContext context = app.Context;
137
138             if (context._Profile == null || (object)context._Profile == (object)ProfileBase.SingletonInstance)
139                 return;
140
141             if (_AutoSaveEventHandler != null) {
142                 ProfileAutoSaveEventArgs args = new ProfileAutoSaveEventArgs(context);
143                 _AutoSaveEventHandler(this, args);
144                 if (!args.ContinueWithProfileAutoSave)
145                     return;
146             }
147
148             context.Profile.Save();
149         }
150
151         ////////////////////////////////////////////////////////////
152         ////////////////////////////////////////////////////////////
153         [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)]
154         internal static void ParseDataFromDB(string[] names, string values, byte[] buf, SettingsPropertyValueCollection properties)
155         {
156             if (names == null || values == null || buf == null || properties == null) 
157                 return;
158             try {
159                 for (int iter = 0; iter < names.Length / 4; iter++) {
160                     string name = names[iter * 4];
161                     SettingsPropertyValue pp = properties[name];
162
163                     if (pp == null) // property not found
164                         continue;
165
166                     int startPos = Int32.Parse(names[iter * 4 + 2], CultureInfo.InvariantCulture);
167                     int length = Int32.Parse(names[iter * 4 + 3], CultureInfo.InvariantCulture);
168
169                     if (length == -1 && !pp.Property.PropertyType.IsValueType) // Null Value
170                     {
171                         pp.PropertyValue = null;
172                         pp.IsDirty = false;
173                         pp.Deserialized = true;
174                     }
175                     if (names[iter * 4 + 1] == "S" && startPos >= 0 && length > 0 && values.Length >= startPos + length) {
176                         pp.SerializedValue = values.Substring(startPos, length);
177                     }
178
179                     if (names[iter * 4 + 1] == "B" && startPos >= 0 && length > 0 && buf.Length >= startPos + length) {
180                         byte[] buf2 = new byte[length];
181
182                         Buffer.BlockCopy(buf, startPos, buf2, 0, length);
183                         pp.SerializedValue = buf2;
184                     }
185                 }
186             } catch { // Eat exceptions
187             }
188         }
189
190         ////////////////////////////////////////////////////////////
191         ////////////////////////////////////////////////////////////
192         ////////////////////////////////////////////////////////////
193         [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)]
194         internal static void PrepareDataForSaving(ref string allNames, ref string allValues, ref byte[] buf, bool binarySupported, SettingsPropertyValueCollection properties, bool userIsAuthenticated)
195         {
196             StringBuilder names = new StringBuilder();
197             StringBuilder values = new StringBuilder();
198
199             MemoryStream ms = (binarySupported ? new System.IO.MemoryStream() : null);
200             try {
201                 try {
202                     bool anyItemsToSave = false;
203
204                     foreach (SettingsPropertyValue pp in properties) {
205                         if (pp.IsDirty) {
206                             if (!userIsAuthenticated) {
207                                 bool allowAnonymous = (bool)pp.Property.Attributes["AllowAnonymous"];
208                                 if (!allowAnonymous)
209                                     continue;
210                             }
211                             anyItemsToSave = true;
212                             break;
213                         }
214                     }
215
216                     if (!anyItemsToSave)
217                         return;
218
219                     foreach (SettingsPropertyValue pp in properties) {
220                         if (!userIsAuthenticated) {
221                             bool allowAnonymous = (bool)pp.Property.Attributes["AllowAnonymous"];
222                             if (!allowAnonymous)
223                                 continue;
224                         }
225
226                         if (!pp.IsDirty && pp.UsingDefaultValue) // Not fetched from DB and not written to
227                             continue;
228
229                         int len = 0, startPos = 0;
230                         string propValue = null;
231
232                         if (pp.Deserialized && pp.PropertyValue == null) // is value null?
233                             {
234                             len = -1;
235                         } else {
236                             object sVal = pp.SerializedValue;
237
238                             if (sVal == null) {
239                                 len = -1;
240                             } else {
241                                 if (!(sVal is string) && !binarySupported) {
242                                     sVal = Convert.ToBase64String((byte[])sVal);
243                                 }
244
245                                 if (sVal is string) {
246                                     propValue = (string)sVal;
247                                     len = propValue.Length;
248                                     startPos = values.Length;
249                                 } else {
250                                     byte[] b2 = (byte[])sVal;
251                                     startPos = (int)ms.Position;
252                                     ms.Write(b2, 0, b2.Length);
253                                     ms.Position = startPos + b2.Length;
254                                     len = b2.Length;
255                                 }
256                             }
257                         }
258
259                         names.Append(pp.Name + ":" + ((propValue != null) ? "S" : "B") +
260                                      ":" + startPos.ToString(CultureInfo.InvariantCulture) + ":" + len.ToString(CultureInfo.InvariantCulture) + ":");
261                         if (propValue != null)
262                             values.Append(propValue);
263                     }
264
265                     if (binarySupported) {
266                         buf = ms.ToArray();
267                     }
268                 } finally {
269                     if (ms != null)
270                         ms.Close();
271                 }
272             } catch {
273                 throw;
274             }
275             allNames = names.ToString();
276             allValues = values.ToString();
277         }
278     }
279
280     public delegate void ProfileMigrateEventHandler(Object sender,  ProfileMigrateEventArgs e);
281
282     public sealed class ProfileMigrateEventArgs : EventArgs {
283         private HttpContext       _Context;
284         private string            _AnonymousId;
285
286         public  HttpContext       Context { get { return _Context;}}
287
288         public  string            AnonymousID { get { return _AnonymousId;}}
289
290         public ProfileMigrateEventArgs(HttpContext context, string anonymousId) {
291             _Context = context;
292             _AnonymousId = anonymousId;
293         }
294     }
295
296     public delegate void ProfileAutoSaveEventHandler(Object sender, ProfileAutoSaveEventArgs e);
297
298     public sealed class ProfileAutoSaveEventArgs : EventArgs
299     {
300         private     HttpContext         _Context;
301         private     bool                _ContinueSave = true;
302
303         public      HttpContext     Context                     { get { return _Context; } }
304         public      bool            ContinueWithProfileAutoSave { get { return _ContinueSave; }  set { _ContinueSave = value; }}
305
306         public ProfileAutoSaveEventArgs(HttpContext context) {
307             _Context = context;
308         }
309     }
310 }