Merge pull request #3040 from xmcclure/debugger-step-recursive
[mono.git] / mcs / class / referencesource / System / compmod / system / componentmodel / design / DesigntimeLicenseContext.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="DesigntimeLicenseContext.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 namespace System.ComponentModel.Design {
8     using System.Runtime.Remoting;
9     using System.Diagnostics;
10     using System;
11     using Microsoft.Win32;
12     using System.Net;
13     using System.IO;
14     using System.Reflection;
15     using System.Collections;
16     using System.ComponentModel;
17     using System.Globalization;
18     using System.Security;
19     using System.Security.Permissions;
20
21     /// <devdoc>
22     ///    <para>
23     ///       Provides design-time support for licensing.
24     ///    </para>
25     /// </devdoc>
26     [HostProtection(SharedState = true)]
27     [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Name = "FullTrust")]
28     [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
29     public class DesigntimeLicenseContext : LicenseContext {
30         internal Hashtable savedLicenseKeys = new Hashtable();
31
32         /// <devdoc>
33         ///    <para>
34         ///       Gets or sets the license usage mode.
35         ///    </para>
36         /// </devdoc>
37         public override LicenseUsageMode UsageMode { 
38             get {
39                 return LicenseUsageMode.Designtime;
40             }
41         }
42         /// <devdoc>
43         ///    <para>
44         ///       Gets a saved license key.
45         ///    </para>
46         /// </devdoc>
47         public override string GetSavedLicenseKey(Type type, Assembly resourceAssembly) {
48             return null;
49         }
50         /// <devdoc>
51         ///    <para>
52         ///       Sets a saved license key.
53         ///    </para>
54         /// </devdoc>
55         public override void SetSavedLicenseKey(Type type, string key) {
56             savedLicenseKeys[type.AssemblyQualifiedName] = key;
57         }
58     }
59
60     [HostProtection(SharedState = true)]
61     internal class RuntimeLicenseContext : LicenseContext
62     {
63         private static TraceSwitch RuntimeLicenseContextSwitch = new TraceSwitch("RuntimeLicenseContextTrace", "RuntimeLicenseContext tracing");
64         const int ReadBlock = 400;
65
66         internal Hashtable savedLicenseKeys;
67
68         /// <devdoc>
69         ///     This method takes a file URL and converts it to a local path.  The trick here is that
70         ///     if there is a '#' in the path, everything after this is treated as a fragment.  So
71         ///     we need to append the fragment to the end of the path.
72         /// </devdoc>
73         private string GetLocalPath(string fileName) {
74             System.Diagnostics.Debug.Assert(fileName != null && fileName.Length > 0, "Cannot get local path, fileName is not valid");
75
76             Uri uri = new Uri(fileName);
77             return uri.LocalPath + uri.Fragment;
78         }
79
80         public override string GetSavedLicenseKey(Type type, Assembly resourceAssembly) {
81
82             if (savedLicenseKeys == null || savedLicenseKeys[type.AssemblyQualifiedName]==null) {
83                 Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose, "savedLicenseKey is null or doesnt contain our type");
84                 if (savedLicenseKeys == null) {
85                     savedLicenseKeys = new Hashtable();
86                 }
87                 
88                 Uri licenseFile = null;
89
90                 if (resourceAssembly == null) {
91                     Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"resourceAssembly is null");
92                     string rawFile = (string)AppDomain.CurrentDomain.SetupInformation.LicenseFile;
93                     Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"rawfile: " + rawFile);
94                     string codeBase;
95                     
96 #if !DISABLE_CAS_USE
97                     // FileIOPermission is required for ApplicationBase in URL-hosted domains
98                     FileIOPermission perm = new FileIOPermission(PermissionState.Unrestricted);
99                     perm.Assert();
100                     try {
101                         codeBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
102                     }
103                     finally {
104                         CodeAccessPermission.RevertAssert();
105                     }
106 #else
107                     codeBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
108 #endif
109                     if (rawFile != null && codeBase != null) {
110                         licenseFile = new Uri(new Uri(codeBase), rawFile);
111                     }
112                 }
113
114                 if (licenseFile == null) {
115                     if(resourceAssembly == null) {
116                         resourceAssembly = Assembly.GetEntryAssembly();
117                     }
118
119                     if (resourceAssembly == null) {
120                         Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"resourceAssembly is null");
121                         // If Assembly.EntryAssembly returns null, then we will 
122                         // try everything!
123                         // 
124                         foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
125
126                             // Though, I could not repro this, we seem to be hitting an AssemblyBuilder
127                             // when walking through all the assemblies in the current app domain. This throws an 
128                             // exception on Assembly.CodeBase and we bail out. Catching exceptions here is not a 
129                             // bad thing.
130                             if (asm.IsDynamic)
131                                 continue;
132
133                             // file://fullpath/foo.exe
134                             //
135                             string fileName;
136 #if !DISABLE_CAS_USE
137                             FileIOPermission perm = new FileIOPermission(PermissionState.Unrestricted);
138                             perm.Assert();
139                             try
140                             {
141                                 fileName = GetLocalPath(asm.EscapedCodeBase);
142                                 fileName = new FileInfo(fileName).Name;
143                             }
144                             finally
145                             {
146                                 CodeAccessPermission.RevertAssert();
147                             }
148 #else
149                             fileName = GetLocalPath(asm.EscapedCodeBase);
150                             fileName = new FileInfo(fileName).Name;
151 #endif
152
153                             Stream s = asm.GetManifestResourceStream(fileName + ".licenses");
154                             if (s == null) {
155                                 //Since the casing may be different depending on how the assembly was loaded, 
156                                 //we'll do a case insensitive lookup for this manifest resource stream...
157                                 s = CaseInsensitiveManifestResourceStreamLookup(asm, fileName + ".licenses");
158                             }
159                             
160                             if (s != null) {
161                                 DesigntimeLicenseContextSerializer.Deserialize(s, fileName.ToUpper(CultureInfo.InvariantCulture), this);
162                                 break;
163                             }
164                         }
165                     }
166                     else if(!resourceAssembly.IsDynamic) { // EscapedCodeBase won't be supported by emitted assemblies anyway
167                         Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"resourceAssembly is not null");
168                         string fileName;
169 #if !DISABLE_CAS_USE
170                         FileIOPermission perm = new FileIOPermission(PermissionState.Unrestricted);
171                         perm.Assert();
172 #endif
173                         try
174                         {
175                             fileName = GetLocalPath(resourceAssembly.EscapedCodeBase);
176                         }
177                         finally
178                         {
179 #if !DISABLE_CAS_USE
180                             CodeAccessPermission.RevertAssert();
181 #endif
182                         }
183                         fileName = Path.GetFileName(fileName); // we don't want to use FileInfo here... it requests FileIOPermission that we
184                         // might now have... see VSWhidbey 527758
185                         string licResourceName = fileName + ".licenses";
186                         // first try the filename
187                         Stream s = resourceAssembly.GetManifestResourceStream(licResourceName);
188                         if (s == null) {
189                             string resolvedName = null;
190                             CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo;
191                             string shortAssemblyName = resourceAssembly.GetName().Name;
192                             //  if the assembly has been renamed, we try our best to find a good match in the available resources
193                             // by looking at the assembly name (which doesn't change even after a file rename) + ".exe.licenses" or + ".dll.licenses"
194                             foreach(String existingName in resourceAssembly.GetManifestResourceNames()) {
195                                 if (comparer.Compare(existingName, licResourceName, CompareOptions.IgnoreCase) == 0 ||
196                                  comparer.Compare(existingName, shortAssemblyName + ".exe.licenses", CompareOptions.IgnoreCase) == 0 || 
197                                  comparer.Compare(existingName, shortAssemblyName + ".dll.licenses", CompareOptions.IgnoreCase) == 0) {
198                                     resolvedName = existingName;
199                                     break;
200                                 }
201                             }
202                             if (resolvedName != null) {
203                                 s = resourceAssembly.GetManifestResourceStream(resolvedName);
204                             }
205                         }
206                         if (s != null) {
207                             DesigntimeLicenseContextSerializer.Deserialize(s, fileName.ToUpper(CultureInfo.InvariantCulture), this);
208                         }
209                     }
210                 }
211
212
213                 if (licenseFile != null) {
214                     Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"licenseFile: " + licenseFile.ToString());
215                     Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"opening licenses file over URI " + licenseFile.ToString());
216                     Stream s = OpenRead(licenseFile);
217                     if (s != null) {
218                         string[] segments = licenseFile.Segments;
219                         string licFileName = segments[segments.Length - 1];
220                         string key = licFileName.Substring(0, licFileName.LastIndexOf("."));
221                         DesigntimeLicenseContextSerializer.Deserialize(s, key.ToUpper(CultureInfo.InvariantCulture), this);
222                     }
223                 }
224
225             }
226             Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"returning : " + (string)savedLicenseKeys[type.AssemblyQualifiedName]);
227             return(string)savedLicenseKeys[type.AssemblyQualifiedName];
228         }
229
230         /**
231         * Looks up a .licenses file in the assembly manifest using 
232         * case-insensitive lookup rules.  We do this because the name
233         * we are attempting to locate could have different casing 
234         * depending on how the assembly was loaded.
235         **/
236         private Stream CaseInsensitiveManifestResourceStreamLookup(Assembly satellite, string name)
237         {
238             CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo;
239             
240             //loop through the resource names in the assembly
241             // we try to handle the case where the assembly file name has been renamed
242             // by trying to guess the original file name based on the assembly name...
243             string assemblyShortName = satellite.GetName().Name;
244             foreach(string existingName in satellite.GetManifestResourceNames()) {
245                 if (comparer.Compare(existingName, name, CompareOptions.IgnoreCase) == 0 ||
246                     comparer.Compare(existingName, assemblyShortName + ".exe.licenses") == 0 ||
247                     comparer.Compare(existingName, assemblyShortName + ".dll.licenses") == 0) {
248                     name = existingName;
249                     break;
250                 }
251             }
252
253             //finally, attempt to return our stream based on the 
254             //case insensitive match we found
255             //
256             return satellite.GetManifestResourceStream(name);
257         }
258
259         static Stream OpenRead(Uri resourceUri) {
260             Stream result = null;
261 #if !DISABLE_CAS_USE
262             PermissionSet perms = new PermissionSet(PermissionState.Unrestricted);
263
264             perms.Assert();
265 #endif
266             try {
267                 WebClient webClient = new WebClient();
268                 webClient.Credentials = CredentialCache.DefaultCredentials;
269                 result = webClient.OpenRead(resourceUri.ToString());
270             }
271             catch (Exception e) {
272                 Debug.Fail(e.ToString());
273             }
274 #if !DISABLE_CAS_USE
275             finally {
276                 CodeAccessPermission.RevertAssert();
277             }
278 #endif
279             return result;
280         }
281     }
282 }
283
284