Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / xsp / System / Web / Configuration / BrowserCapabilitiesCodeGenerator.cs / 3 / BrowserCapabilitiesCodeGenerator.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Web.Configuration { using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Configuration; using System.Collections; using System.Collections.Specialized; using System.IO; #if !FEATURE_PAL using System.ServiceProcess; #endif // !FEATURE_PAL using System.Reflection; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Web; using System.Web.Compilation; using System.Web.Configuration; using System.Web.Hosting; using System.Web.UI; using System.Web.Util; using System.Xml; using System.Xml.Schema; using Microsoft.CSharp; [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)] [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)] public class BrowserCapabilitiesCodeGenerator { private static readonly string _browsersDirectory; private static readonly string _publicKeyTokenFile; private static object _staticLock = new object(); private BrowserTree _browserTree; private BrowserTree _defaultTree; private BrowserDefinitionCollection _browserDefinitionCollection; internal const string browserCapsVariable = "browserCaps"; internal const string IgnoreApplicationBrowserVariableName = "ignoreApplicationBrowsers"; private const string _factoryTypeName = "BrowserCapabilitiesFactory"; private const string _headerDictionaryVarName = "_headerDictionary"; private const string _disableOptimizedCacheKeyMethodName = "DisableOptimizedCacheKey"; private const string _matchedHeadersMethodName = "PopulateMatchedHeaders"; private const string _browserElementsMethodName = "PopulateBrowserElements"; private const string _dictionaryRefName = "dictionary"; private const string _regexWorkerRefName = "regexWorker"; private const string _headersRefName = "headers"; private const string _resultVarName = "result"; private const string _processRegexMethod = "ProcessRegex"; private static readonly string _strongNameKeyFileName = browserCapsVariable + ".snk"; private static readonly string _publicKeyTokenFileName = browserCapsVariable + ".token"; private static bool _publicKeyTokenLoaded; private static string _publicKeyToken; private CodeVariableReferenceExpression _dictionaryRefExpr = new CodeVariableReferenceExpression(_dictionaryRefName); private CodeVariableReferenceExpression _regexWorkerRefExpr = new CodeVariableReferenceExpression(_regexWorkerRefName); private CodeVariableReferenceExpression _headersRefExpr = new CodeVariableReferenceExpression(_headersRefName); private CodeVariableReferenceExpression _browserCapsRefExpr = new CodeVariableReferenceExpression(browserCapsVariable); private ArrayList _browserFileList; private ArrayList _customBrowserFileLists; private ArrayList _customTreeList; private ArrayList _customTreeNames; private ArrayList _customBrowserDefinitionCollections; private CaseInsensitiveStringSet _headers; static BrowserCapabilitiesCodeGenerator() { #if !PLATFORM_UNIX // File system paths must account for UNIX _browsersDirectory = HttpRuntime.ClrInstallDirectoryInternal + "\\config\\browsers"; _publicKeyTokenFile = _browsersDirectory + "\\" + _publicKeyTokenFileName; #else // !PLATFORM_UNIX _browsersDirectory = HttpRuntime.ClrInstallDirectoryInternal + "/config/browsers"; _publicKeyTokenFile = _browsersDirectory + "/" + _publicKeyTokenFileName; #endif // !PLATFORM_UNIX } public BrowserCapabilitiesCodeGenerator() { _headers = new CaseInsensitiveStringSet(); } internal BrowserTree BrowserTree { get { return _browserTree; } } internal BrowserTree DefaultTree { get { return _defaultTree; } } internal ArrayList CustomTreeList { get { return _customTreeList; } } internal ArrayList CustomTreeNames { get { return _customTreeNames; } } internal static string BrowserCapAssemblyPublicKeyToken { get { if (_publicKeyTokenLoaded) { return _publicKeyToken; } lock (_staticLock) { if (_publicKeyTokenLoaded) { return _publicKeyToken; } _publicKeyToken = LoadPublicKeyTokenFromFile(_publicKeyTokenFile); _publicKeyTokenLoaded = true; return _publicKeyToken; } } } internal virtual bool GenerateOverrides { get { return true; } } internal virtual string TypeName { get { return _factoryTypeName; } } internal void AddFile(string filePath) { if (_browserFileList == null) _browserFileList = new ArrayList(); _browserFileList.Add(filePath); } internal void AddCustomFile(string filePath) { if (_customBrowserFileLists == null) { _customBrowserFileLists = new ArrayList(); } _customBrowserFileLists.Add(filePath); } //parse the config info and create BrowserTree //then generate code for, compile, and gac the object [SecurityPermission(SecurityAction.Demand, Unrestricted=true)] public virtual void Create() { DirectoryInfo browserDirInfo = new DirectoryInfo(_browsersDirectory); //get all the browser files and put them in the "tree" FileInfo[] browserFiles = browserDirInfo.GetFiles("*.browser"); if (browserFiles == null || browserFiles.Length == 0) { return; } foreach(FileInfo browserFile in browserFiles) { AddFile(browserFile.FullName); } // First parse the browser files. ProcessBrowserFiles(); // Then parse custom browser files. ProcessCustomBrowserFiles(); // Uninstall previously installed generated assembly. Uninstall(); //generate the source code, compile it, and gac it GenerateAssembly(); // Restart w3svc service RestartW3SVCIfNecessary(); } internal bool UninstallInternal() { // Remove existing strong name public token file if (File.Exists(_publicKeyTokenFile)) { File.Delete(_publicKeyTokenFile); } // Removing existing copy from GAC GacUtil gacutil = new GacUtil(); bool assemblyRemoved = gacutil.GacUnInstall("ASP.BrowserCapsFactory, Version=" + ThisAssembly.Version + ", Culture=neutral"); if (!assemblyRemoved) { return false; } return true; } [SecurityPermission(SecurityAction.Demand, Unrestricted = true)] public bool Uninstall() { // Restart w3svc service RestartW3SVCIfNecessary(); if (!UninstallInternal()) { return false; } // Restart w3svc service again so applications get a fresh copy. RestartW3SVCIfNecessary(); return true; } private void RestartW3SVCIfNecessary() { #if !FEATURE_PAL try { ServiceController controller = new ServiceController("W3SVC"); ServiceControllerStatus status = controller.Status; // Stop the service if it's not currently stopped or pending. if (!status.Equals(ServiceControllerStatus.Stopped) && !status.Equals(ServiceControllerStatus.StopPending) && !status.Equals(ServiceControllerStatus.StartPending)) { controller.Stop(); // Give it 5 minutes to stop controller.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 5, 0)); controller.Start(); // If the service was paused, pause it. if (status.Equals(ServiceControllerStatus.Paused) || status.Equals(ServiceControllerStatus.PausePending)) { controller.Pause(); } } } catch (Exception ex) { throw new InvalidOperationException(SR.GetString(SR.Browser_W3SVC_Failure_Helper_Text, ex)); } #endif // !FEATURE_PAL } internal void ProcessBrowserFiles() { ProcessBrowserFiles(false, String.Empty); } private string NoPathFileName(string fullPath) { int lastSlash = fullPath.LastIndexOf("\\", StringComparison.Ordinal); if(lastSlash > -1) { return fullPath.Substring(lastSlash + 1); } return fullPath; } internal virtual void ProcessBrowserNode(XmlNode node, BrowserTree browserTree) { BrowserDefinition browserInfo = null; if (node.Name == "gateway") { browserInfo = new GatewayDefinition(node); } else if (node.Name == "browser") { browserInfo = new BrowserDefinition(node); } else { Debug.Assert(node.Name == "defaultBrowser"); browserInfo = new BrowserDefinition(node, true); } BrowserDefinition oldNode = (BrowserDefinition)browserTree[browserInfo.Name]; if (oldNode != null) { if (browserInfo.IsRefID) { oldNode.MergeWithDefinition(browserInfo); } else { throw new ConfigurationErrorsException(SR.GetString(SR.Duplicate_browser_id, browserInfo.ID), node); } } else { browserTree[browserInfo.Name] = browserInfo; } } private void NormalizeAndValidateTree(BrowserTree browserTree, bool isDefaultBrowser) { NormalizeAndValidateTree(browserTree, isDefaultBrowser, false); } private void NormalizeAndValidateTree(BrowserTree browserTree, bool isDefaultBrowser, bool isCustomBrowser) { //normalize the tree foreach (DictionaryEntry entry in browserTree) { BrowserDefinition bd = (BrowserDefinition)entry.Value; string parentName = bd.ParentName; BrowserDefinition parentBrowser = null; if (IsRootNode(bd.Name)) { continue; } if (parentName.Length > 0) { parentBrowser = (BrowserDefinition)browserTree[parentName]; } if (parentBrowser != null) { if (bd.IsRefID) { if (bd is GatewayDefinition) { parentBrowser.RefGateways.Add(bd); } else { parentBrowser.RefBrowsers.Add(bd); } } else if (bd is GatewayDefinition) { parentBrowser.Gateways.Add(bd); } else { parentBrowser.Browsers.Add(bd); } } else { if (isCustomBrowser) { throw new ConfigurationErrorsException(SR.GetString(SR.Browser_parentID_Not_Found, bd.ParentID), bd.XmlNode); } else { HandleUnRecognizedParentElement(bd, isDefaultBrowser); } } } //validate the tree //loop check foreach (DictionaryEntry entry in browserTree) { BrowserDefinition bd = (BrowserDefinition)entry.Value; Hashtable loopCheck = new Hashtable(); BrowserDefinition currentBrowser = bd; string currentId = currentBrowser.Name; while (!IsRootNode(currentId)) { if (loopCheck[currentId] != null) { throw new ConfigurationErrorsException(SR.GetString(SR.Browser_Circular_Reference, currentId), currentBrowser.XmlNode); } loopCheck[currentId] = currentId; currentBrowser = (BrowserDefinition)browserTree[currentBrowser.ParentName]; //in app-level, parent can exist in machine level if (currentBrowser == null) { break; } currentId = currentBrowser.Name; } } } private void SetCustomTreeRoots(BrowserTree browserTree, int index) { foreach (DictionaryEntry entry in browserTree) { BrowserDefinition bd = (BrowserDefinition)entry.Value; if (bd.ParentName == null) { _customTreeNames[index] = bd.Name; break; } } } // Now that we support adding custom browser hierarchies, root nodes other than Default are permitted. private bool IsRootNode(string nodeName) { if (String.Compare(nodeName, "Default", StringComparison.OrdinalIgnoreCase) == 0) return true; foreach (string treeRootName in _customTreeNames) { if (String.Compare(nodeName, treeRootName, StringComparison.OrdinalIgnoreCase) == 0) { return true; } } return false; } protected void ProcessBrowserFiles(bool useVirtualPath, string virtualDir) { _browserTree = new BrowserTree(); _defaultTree = new BrowserTree(); _customTreeNames = new ArrayList(); if (_browserFileList == null) { _browserFileList = new ArrayList(); } _browserFileList.Sort(); //#if OPTIMIZE_FOR_DESKTOP_BROWSER string mozillaFile = null; string ieFile = null; string operaFile = null; // DevDivBugs 180962 // IE, Mozilla and Opera are first-class browsers. Their User-Agent profiles need to be compared to the UA profile // of the HTTP request before other browsers. We put them to the head of the list so that the generated browser capabilities // code will try to match them before other browsers. foreach (String filePath in _browserFileList) { if (filePath.EndsWith("ie.browser", StringComparison.OrdinalIgnoreCase)) { ieFile = filePath; } else if (filePath.EndsWith("mozilla.browser", StringComparison.OrdinalIgnoreCase)) { mozillaFile = filePath; } else if (filePath.EndsWith("opera.browser", StringComparison.OrdinalIgnoreCase)) { operaFile = filePath; break; } } if (ieFile != null) { _browserFileList.Remove(ieFile); _browserFileList.Insert(0, ieFile); } if (mozillaFile != null) { _browserFileList.Remove(mozillaFile); _browserFileList.Insert(1, mozillaFile); } if (operaFile != null) { _browserFileList.Remove(operaFile); _browserFileList.Insert(2, operaFile); } //#endif foreach (string fileName in _browserFileList) { XmlDocument doc = new ConfigXmlDocument(); try { doc.Load(fileName); XmlNode rootNode = doc.DocumentElement; if(rootNode.Name != "browsers") { if(useVirtualPath) { throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, 1); } else { throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, fileName, null /*sourceCode*/, 1); } } foreach (XmlNode node in rootNode.ChildNodes) { if (node.NodeType != XmlNodeType.Element) continue; if (node.Name == "browser" || node.Name == "gateway") { ProcessBrowserNode(node, _browserTree); } else if (node.Name == "defaultBrowser") { ProcessBrowserNode(node, _defaultTree); } else { HandlerBase.ThrowUnrecognizedElement(node); } } } catch (XmlException e) { if(useVirtualPath) { throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber); } else { throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); } } catch (XmlSchemaException e) { if(useVirtualPath) { string noPathFileName = String.Empty; int lastSlash = fileName.LastIndexOf("\\", StringComparison.Ordinal); if(lastSlash > -1) { noPathFileName = fileName.Substring(lastSlash); } throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber); } else { throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); } } } NormalizeAndValidateTree(_browserTree, false); NormalizeAndValidateTree(_defaultTree, true); BrowserDefinition defaultBrowser = (BrowserDefinition)_browserTree["Default"]; if (defaultBrowser != null) { AddBrowserToCollectionRecursive(defaultBrowser, 0); } } internal void ProcessCustomBrowserFiles() { ProcessCustomBrowserFiles(false, String.Empty); } internal void ProcessCustomBrowserFiles(bool useVirtualPath, string virtualDir) { //get all custom browser files and put them in the "tree" DirectoryInfo browserDirInfo = null; DirectoryInfo[] browserSubDirectories = null; ArrayList customBrowserFileNames; _customTreeList = new ArrayList(); _customBrowserFileLists = new ArrayList(); _customBrowserDefinitionCollections = new ArrayList(); /* Machine Level Custom Browsers */ if (useVirtualPath == false) { browserDirInfo = new DirectoryInfo(_browsersDirectory); } /* Application Level Custom Browsers */ else { browserDirInfo = new DirectoryInfo(HostingEnvironment.MapPathInternal(virtualDir)); } browserSubDirectories = browserDirInfo.GetDirectories(); for (int i = 0; i < browserSubDirectories.Length; i++) { /* Recursively Into Subdirectories */ FileInfo[] browserFiles = browserSubDirectories[i].GetFiles("*.browser", SearchOption.AllDirectories); if (browserFiles == null || browserFiles.Length == 0) { continue; } BrowserTree customTree = new BrowserTree(); _customTreeList.Add(customTree); _customTreeNames.Add(browserSubDirectories[i].Name); customBrowserFileNames = new ArrayList(); foreach (FileInfo browserFile in browserFiles) { customBrowserFileNames.Add(browserFile.FullName); } _customBrowserFileLists.Add(customBrowserFileNames); } for (int i = 0; i < _customBrowserFileLists.Count; i++) { ArrayList fileNames = (ArrayList)_customBrowserFileLists[i]; foreach (string fileName in fileNames) { XmlDocument doc = new ConfigXmlDocument(); try { doc.Load(fileName); XmlNode rootNode = doc.DocumentElement; if (rootNode.Name != "browsers") { if (useVirtualPath) { throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, 1); } else { throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, fileName, null /*sourceCode*/, 1); } } foreach (XmlNode node in rootNode.ChildNodes) { if (node.NodeType != XmlNodeType.Element) { continue; } if (node.Name == "browser" || node.Name == "gateway") { ProcessBrowserNode(node, (BrowserTree)_customTreeList[i]); } else { HandlerBase.ThrowUnrecognizedElement(node); } } } catch (XmlException e) { if (useVirtualPath) { throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber); } else { throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); } } catch (XmlSchemaException e) { if (useVirtualPath) { string noPathFileName = String.Empty; int lastSlash = fileName.LastIndexOf("\\", StringComparison.Ordinal); if (lastSlash > -1) { noPathFileName = fileName.Substring(lastSlash); } throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber); } else { throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); } } } SetCustomTreeRoots((BrowserTree)_customTreeList[i], i); NormalizeAndValidateTree((BrowserTree)_customTreeList[i], false, true); _customBrowserDefinitionCollections.Add(new BrowserDefinitionCollection()); AddCustomBrowserToCollectionRecursive((BrowserDefinition)(((BrowserTree)_customTreeList[i])[_customTreeNames[i]]), 0, i); } } internal void AddCustomBrowserToCollectionRecursive(BrowserDefinition bd, int depth, int index) { if(_customBrowserDefinitionCollections[index] == null) { _customBrowserDefinitionCollections[index] = new BrowserDefinitionCollection(); } bd.Depth = depth; bd.IsDeviceNode = true; ((BrowserDefinitionCollection)_customBrowserDefinitionCollections[index]).Add(bd); foreach (BrowserDefinition childBrowser in bd.Browsers) { AddCustomBrowserToCollectionRecursive(childBrowser, depth + 1, index); } } internal void AddBrowserToCollectionRecursive(BrowserDefinition bd, int depth) { if (_browserDefinitionCollection == null) { _browserDefinitionCollection = new BrowserDefinitionCollection(); } bd.Depth = depth; bd.IsDeviceNode = true; _browserDefinitionCollection.Add(bd); foreach(BrowserDefinition childBrowser in bd.Browsers) { AddBrowserToCollectionRecursive(childBrowser, depth + 1); } } internal virtual void HandleUnRecognizedParentElement(BrowserDefinition bd, bool isDefault) { throw new ConfigurationErrorsException(SR.GetString(SR.Browser_parentID_Not_Found, bd.ParentID), bd.XmlNode); } //generate the code from the parsed BrowserDefinitionTree //compile it, and install it in the gac private void GenerateAssembly() { Debug.Assert(_browserTree != null); BrowserDefinition root = (BrowserDefinition)_browserTree["Default"]; BrowserDefinition defaultRoot = (BrowserDefinition)_defaultTree["Default"]; ArrayList customTreeRoots = new ArrayList(); for (int i = 0; i < _customTreeNames.Count; i++) { customTreeRoots.Add((BrowserDefinition)(((BrowserTree)_customTreeList[i])[_customTreeNames[i]])); } //create a CodeCompileUnit //add a CodeNamespace object to the CodeCompileUnit //add a CodeTypeDeclaration to the CodeNamespace //add all the members of the type/class to the CodeTypeDeclaration //use a CodeGenerator to generate code from the CodeCompileUnit //a CodeDomProvider can provide a CodeGenerator //translate the BrowserDefinition tree to code CSharpCodeProvider cscp = new CSharpCodeProvider(); // namespace System.Web.BrowserCapsFactory CodeCompileUnit ccu = new CodeCompileUnit(); //add strong-name key pair for CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( "System.Reflection.AssemblyKeyFile", new CodeAttributeArgument[] { new CodeAttributeArgument(new CodePrimitiveExpression(_strongNameKeyFileName))}); CodeAttributeDeclaration aptca = new CodeAttributeDeclaration( "System.Security.AllowPartiallyTrustedCallers"); ccu.AssemblyCustomAttributes.Add(aptca); ccu.AssemblyCustomAttributes.Add(declaration); //add version number for it so it can distinguished in future versions declaration = new CodeAttributeDeclaration( "System.Reflection.AssemblyVersion", new CodeAttributeArgument[] { new CodeAttributeArgument(new CodePrimitiveExpression(ThisAssembly.Version))}); ccu.AssemblyCustomAttributes.Add(declaration); CodeNamespace cnamespace = new CodeNamespace("ASP"); //GEN: using System; cnamespace.Imports.Add(new CodeNamespaceImport("System")); //GEN: using System.Web; cnamespace.Imports.Add(new CodeNamespaceImport("System.Web")); //GEN: using System.Web.Configuration; cnamespace.Imports.Add(new CodeNamespaceImport("System.Web.Configuration")); //GEN: using System.Reflection; cnamespace.Imports.Add(new CodeNamespaceImport("System.Reflection")); //GEN: class BrowserCapabilitiesFactory ccu.Namespaces.Add(cnamespace); CodeTypeDeclaration factoryType = new CodeTypeDeclaration("BrowserCapabilitiesFactory"); factoryType.Attributes = MemberAttributes.Private; factoryType.IsClass = true; factoryType.Name = TypeName; factoryType.BaseTypes.Add(new CodeTypeReference("System.Web.Configuration.BrowserCapabilitiesFactoryBase")); cnamespace.Types.Add(factoryType); //GEN: protected override object ConfigureBrowserCapabilities(NameValueCollection headers, HttpBrowserCapabilities browserCaps) CodeMemberMethod method = new CodeMemberMethod(); method.Attributes = MemberAttributes.Override | MemberAttributes.Public; method.ReturnType = new CodeTypeReference(typeof(void)); method.Name = "ConfigureBrowserCapabilities"; CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName); method.Parameters.Add(cpde); cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable); method.Parameters.Add(cpde); factoryType.Members.Add(method); GenerateSingleProcessCall(root, method); for (int i = 0; i < customTreeRoots.Count; i++) { GenerateSingleProcessCall((BrowserDefinition)customTreeRoots[i], method); } //GEN: if(this.IsBrowserUnknown(browserCaps) == false) return; CodeConditionStatement istatement = new CodeConditionStatement(); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "IsBrowserUnknown"); cmie.Parameters.Add(_browserCapsRefExpr); istatement.Condition = new CodeBinaryOperatorExpression(cmie, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); istatement.TrueStatements.Add(new CodeMethodReturnStatement()); method.Statements.Add(istatement); if(defaultRoot != null) { GenerateSingleProcessCall(defaultRoot, method, "Default"); } for (int i = 0; i < customTreeRoots.Count; i++) { foreach (DictionaryEntry entry in (BrowserTree)_customTreeList[i]) { BrowserDefinition bd = entry.Value as BrowserDefinition; Debug.Assert(bd != null); GenerateProcessMethod(bd, factoryType); } } //GenerateCallsToProcessMethods(root, method); foreach (DictionaryEntry entry in _browserTree) { BrowserDefinition bd = entry.Value as BrowserDefinition; Debug.Assert(bd != null); GenerateProcessMethod(bd, factoryType); } foreach (DictionaryEntry entry in _defaultTree) { BrowserDefinition bd = entry.Value as BrowserDefinition; Debug.Assert(bd != null); GenerateProcessMethod(bd, factoryType, "Default"); } GenerateOverrideMatchedHeaders(factoryType); GenerateOverrideBrowserElements(factoryType); // TextWriter twriter = new StreamWriter(new FileStream(_browsersDirectory + "\\BrowserCapsFactory.cs", FileMode.Create)); try { cscp.GenerateCodeFromCompileUnit(ccu, twriter, null); } finally { if(twriter != null) twriter.Close(); } CompilationSection compConfig = RuntimeConfig.GetAppConfig().Compilation; bool debug = compConfig.Debug; #if !PLATFORM_UNIX // File system paths must account for UNIX string strongNameFile = _browsersDirectory + "\\" + _strongNameKeyFileName; #else // !PLATFORM_UNIX string strongNameFile = _browsersDirectory + "/" + _strongNameKeyFileName; #endif // !PLATFORM_UNIX // Generate strong name file StrongNameUtility.GenerateStrongNameFile(strongNameFile); // string[] referencedAssemblies = new string[2] { "System.dll", "System.Web.dll" }; CompilerParameters compilerParameters = new CompilerParameters(referencedAssemblies, "ASP.BrowserCapsFactory", debug /* includeDebugInformation */ ); compilerParameters.GenerateInMemory = false; compilerParameters.OutputAssembly = _browsersDirectory + "\\ASP.BrowserCapsFactory.dll"; CompilerResults results = null; try { results = cscp.CompileAssemblyFromFile(compilerParameters, _browsersDirectory + "\\BrowserCapsFactory.cs"); } finally { if (File.Exists(strongNameFile)) { File.Delete(strongNameFile); } } if (results.NativeCompilerReturnValue != 0 || results.Errors.HasErrors) { foreach (CompilerError error in results.Errors) { if (!error.IsWarning) { throw new HttpCompileException(error.ErrorText); } } throw new HttpCompileException(SR.GetString(SR.Browser_compile_error)); } Assembly resultAssembly = results.CompiledAssembly; GacUtil gacutil = new GacUtil(); gacutil.GacInstall(resultAssembly.Location); SavePublicKeyTokenFile(_publicKeyTokenFile, resultAssembly.GetName().GetPublicKeyToken()); } private void SavePublicKeyTokenFile(string filename, byte[] publicKeyToken) { using (FileStream pktStream = new FileStream(filename, FileMode.Create, FileAccess.Write)) { using (StreamWriter pktWriter = new StreamWriter(pktStream)) { foreach (byte b in publicKeyToken) { pktWriter.Write("{0:X2}", b); } } } } private static string LoadPublicKeyTokenFromFile(string filename) { IStackWalk fileReadAccess = InternalSecurityPermissions.FileReadAccess(filename); Debug.Assert(fileReadAccess != null); fileReadAccess.Assert(); if (!File.Exists(filename)) { return null; } try { using (FileStream pktStream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { using (StreamReader pktReader = new StreamReader(pktStream)) { return pktReader.ReadLine(); } } } catch (IOException) { if (HttpRuntime.HasFilePermission(filename)) { throw; } // Don't throw exception if we don't have permission to the file. return null; } finally { CodeAccessPermission.RevertAssert(); } } internal void GenerateOverrideBrowserElements(CodeTypeDeclaration typeDeclaration) { // Don't generate the property if there's nothing to override. if (_browserDefinitionCollection == null) { return; } // GEN: // protected override void PopulateBrowserElements(IDictionary dictionary) { // dictionary["Default"] = new Triplet(null, "default description", 0 /*depth_of_node */); // dictionary["Up"] = new Triplet("Default", "up Description", 1 /*depth_of_node */); // } CodeMemberMethod method = new CodeMemberMethod(); method.Name = _browserElementsMethodName; method.Attributes = MemberAttributes.Override | MemberAttributes.Family; method.ReturnType = new CodeTypeReference(typeof(void)); CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IDictionary)), _dictionaryRefName); method.Parameters.Add(parameter); typeDeclaration.Members.Add(method); CodeMethodReferenceExpression baseMethod = new CodeMethodReferenceExpression(new CodeBaseReferenceExpression(), _browserElementsMethodName); CodeMethodInvokeExpression baseInvoke = new CodeMethodInvokeExpression(baseMethod, new CodeExpression[] { _dictionaryRefExpr }); method.Statements.Add(baseInvoke); foreach(BrowserDefinition bd in _browserDefinitionCollection) { if (!bd.IsDeviceNode) continue; Debug.Assert(!(bd is GatewayDefinition)); CodeAssignStatement cas = new CodeAssignStatement(); cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(bd.ID) }); cas.Right = new CodeObjectCreateExpression(typeof(Triplet), new CodeExpression[] { new CodePrimitiveExpression(bd.ParentName), new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty"), new CodePrimitiveExpression(bd.Depth)}); method.Statements.Add(cas); } for (int i = 0; i < _customTreeNames.Count; i++) { foreach (BrowserDefinition bd in (BrowserDefinitionCollection)_customBrowserDefinitionCollections[i]) { if (!bd.IsDeviceNode) continue; Debug.Assert(!(bd is GatewayDefinition)); CodeAssignStatement cas = new CodeAssignStatement(); cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(bd.ID) }); cas.Right = new CodeObjectCreateExpression(typeof(Triplet), new CodeExpression[] { new CodePrimitiveExpression(bd.ParentName), new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty"), new CodePrimitiveExpression(bd.Depth)}); method.Statements.Add(cas); } } } internal void GenerateOverrideMatchedHeaders(CodeTypeDeclaration typeDeclaration) { // GEN: // protected override void PopulateMatchedHeaders(IDictionary dictionary) { // base.PopulateMatchedHeaders(dictionary); // // dictionary["header0"] = null; // dictionary["header1"] = null; // } CodeMemberMethod method = new CodeMemberMethod(); method.Name = _matchedHeadersMethodName; method.Attributes = MemberAttributes.Override | MemberAttributes.Family; method.ReturnType = new CodeTypeReference(typeof(void)); CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IDictionary)), _dictionaryRefName); method.Parameters.Add(parameter); typeDeclaration.Members.Add(method); CodeMethodReferenceExpression baseMethod = new CodeMethodReferenceExpression(new CodeBaseReferenceExpression(), _matchedHeadersMethodName); CodeMethodInvokeExpression baseInvoke = new CodeMethodInvokeExpression(baseMethod, new CodeExpression[] { _dictionaryRefExpr }); method.Statements.Add(baseInvoke); foreach(String header in _headers) { CodeAssignStatement cas = new CodeAssignStatement(); cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(header) }); cas.Right = new CodePrimitiveExpression(null); method.Statements.Add(cas); } } internal void GenerateProcessMethod(BrowserDefinition bd, CodeTypeDeclaration ctd) { GenerateProcessMethod(bd, ctd, String.Empty); } //generate the xxxProcess method for an individual BrowserDefinition internal void GenerateProcessMethod(BrowserDefinition bd, CodeTypeDeclaration ctd, string prefix) { //GEN: internal bool XxxProcess(NameValueCollection headers, HttpBrowserCapabilities browserCaps) CodeMemberMethod cmm = new CodeMemberMethod(); cmm.Name = prefix + bd.Name + "Process"; cmm.ReturnType = new CodeTypeReference(typeof(bool)); cmm.Attributes = MemberAttributes.Private; CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName); cmm.Parameters.Add(cpde); cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable); cmm.Parameters.Add(cpde); bool regexWorkerGenerated = false; GenerateIdentificationCode(bd, cmm, ref regexWorkerGenerated); GenerateCapturesCode(bd, cmm, ref regexWorkerGenerated); GenerateSetCapabilitiesCode(bd, cmm, ref regexWorkerGenerated); GenerateSetAdaptersCode(bd, cmm); // Only add the browser node to the browser collection if it represents a device. if (bd.IsDeviceNode) { Debug.Assert(!(bd is GatewayDefinition)); //GEN: browserCaps.AddBrowser("xxx"); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression(browserCapsVariable), "AddBrowser"); cmie.Parameters.Add(new CodePrimitiveExpression(bd.ID)); cmm.Statements.Add(cmie); } // Generate ref gateway elements foreach (BrowserDefinition b in bd.RefGateways) { AddComment("ref gateways, parent=" + bd.ID, cmm); GenerateSingleProcessCall(b, cmm); } if ((GenerateOverrides) && (prefix.Length == 0)) { //Gen: protected virtual void XxxProcessGateways(NameValueCollection headers, HttpBrowserCapabilities browserCaps) ; string methodName = prefix + bd.Name + "ProcessGateways"; GenerateChildProcessMethod(methodName, ctd, false); //Gen: XxxProcessGateways(headers, browserCaps) ; GenerateChildProcessInvokeExpression(methodName, cmm, false); } foreach(BrowserDefinition b in bd.Gateways) { AddComment("gateway, parent=" + bd.ID, cmm); GenerateSingleProcessCall(b, cmm); } if (GenerateOverrides) { //GEN: bool ignoreApplicationBrowsers = true | false; //bd.Browsers.Count != 0 CodeVariableDeclarationStatement cvds = new CodeVariableDeclarationStatement(typeof(bool), IgnoreApplicationBrowserVariableName, new CodePrimitiveExpression(bd.Browsers.Count != 0)); cmm.Statements.Add(cvds); } if (bd.Browsers.Count > 0) { CodeStatementCollection statements = cmm.Statements; AddComment("browser, parent=" + bd.ID, cmm); foreach (BrowserDefinition b in bd.Browsers) { statements = GenerateTrackedSingleProcessCall(statements, b, cmm, prefix); } if (GenerateOverrides) { //GEN: ignoreApplicationBrowsers = false; CodeAssignStatement codeAssignStmt = new CodeAssignStatement(); codeAssignStmt.Left = new CodeVariableReferenceExpression(IgnoreApplicationBrowserVariableName); codeAssignStmt.Right = new CodePrimitiveExpression(false); statements.Add(codeAssignStmt); } } // Generate ref browser foreach (BrowserDefinition b in bd.RefBrowsers) { AddComment("ref browsers, parent=" + bd.ID, cmm); if (b.IsDefaultBrowser) { GenerateSingleProcessCall(b, cmm, "Default"); } else { GenerateSingleProcessCall(b, cmm); } } if (GenerateOverrides) { //Gen: protected virtual void XxxProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps) ; string methodName = prefix + bd.Name + "ProcessBrowsers"; GenerateChildProcessMethod(methodName, ctd, true); //Gen: XxxProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps); GenerateChildProcessInvokeExpression(methodName, cmm, true); } //GEN: return true; CodeMethodReturnStatement cmrs = new CodeMethodReturnStatement(new CodePrimitiveExpression(true)); cmm.Statements.Add(cmrs); ctd.Members.Add(cmm); } private void GenerateChildProcessInvokeExpression(string methodName, CodeMemberMethod cmm, bool generateTracker) { //Gen: XxxProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps) ; CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), methodName); if (generateTracker) { expr.Parameters.Add(new CodeVariableReferenceExpression(IgnoreApplicationBrowserVariableName)); } expr.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName)); expr.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable)); cmm.Statements.Add(expr); } private void GenerateChildProcessMethod(string methodName, CodeTypeDeclaration ctd, bool generateTracker) { //Gen: protected virtual void XxxProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps) ; CodeMemberMethod cmm= new CodeMemberMethod(); cmm.Name = methodName; cmm.ReturnType = new CodeTypeReference(typeof(void)); cmm.Attributes = MemberAttributes.Family; CodeParameterDeclarationExpression cpde = null; if (generateTracker) { cpde = new CodeParameterDeclarationExpression(typeof(bool), IgnoreApplicationBrowserVariableName); cmm.Parameters.Add(cpde); } cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName); cmm.Parameters.Add(cpde); cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable); cmm.Parameters.Add(cpde); ctd.Members.Add(cmm); } private void GenerateRegexWorkerIfNecessary(CodeMemberMethod cmm, ref bool regexWorkerGenerated) { if (regexWorkerGenerated) { return; } regexWorkerGenerated = true; //GEN: RegexWorker regexWorker; cmm.Statements.Add(new CodeVariableDeclarationStatement("RegexWorker", _regexWorkerRefName)); //GEN: regexWorker = new RegexWorker(browserCaps); cmm.Statements.Add(new CodeAssignStatement(_regexWorkerRefExpr, new CodeObjectCreateExpression("RegexWorker", _browserCapsRefExpr))); } private void ReturnIfHeaderValueEmpty(CodeMemberMethod cmm, CodeVariableReferenceExpression varExpr) { // GEN: if(String.IsNullOrEmpty(varExpr)) { // GEN: return false; // GEN: } CodeConditionStatement emptyCheckStmt = new CodeConditionStatement(); CodeMethodReferenceExpression emptyCheckMethod = new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "IsNullOrEmpty"); CodeMethodInvokeExpression emptyCheckExpr = new CodeMethodInvokeExpression(emptyCheckMethod, varExpr); emptyCheckStmt.Condition = emptyCheckExpr; emptyCheckStmt.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); cmm.Statements.Add(emptyCheckStmt); } //generate part of the xxxProcess method for handling determining if the requesting //browser meets the regexes for this browser private void GenerateIdentificationCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) { //GEN: IDictionary dictionary; cmm.Statements.Add(new CodeVariableDeclarationStatement(typeof(IDictionary), _dictionaryRefName)); //GEN: dictionary = browserCaps.Capabilities; CodeAssignStatement assign = new CodeAssignStatement( _dictionaryRefExpr, new CodePropertyReferenceExpression(_browserCapsRefExpr, "Capabilities") ); cmm.Statements.Add(assign); bool disableOptimizedKey = false; CodeVariableReferenceExpression result = null; CodeVariableReferenceExpression headerValue = null; if(bd.IdHeaderChecks.Count > 0) { AddComment("Identification: check header matches", cmm); for (int i = 0; i < bd.IdHeaderChecks.Count; i++) { string matchedString = ((CheckPair)bd.IdHeaderChecks[i]).MatchString; // Skip matching ".*" if (matchedString.Equals(".*")) { continue; } if (headerValue == null) { headerValue = GenerateVarReference(cmm, typeof(string), "headerValue"); } CodeAssignStatement valueAssignment = new CodeAssignStatement(); cmm.Statements.Add(valueAssignment); valueAssignment.Left = headerValue; if (((CheckPair)bd.IdHeaderChecks[i]).Header.Equals("User-Agent")) { _headers.Add(String.Empty); // GEN: headerValue = ((string)(browserCaps[String.Empty])); valueAssignment.Right = new CodeCastExpression(typeof(string), new CodeIndexerExpression( new CodeVariableReferenceExpression(browserCapsVariable), new CodeExpression[] { new CodePropertyReferenceExpression( new CodeTypeReferenceExpression(typeof(String)), "Empty") })); } else { string header = ((CheckPair)bd.IdHeaderChecks[i]).Header; _headers.Add(header); //GEN: headerValue = ((String)headers["xxx"]); valueAssignment.Right = new CodeCastExpression(typeof(string), new CodeIndexerExpression( _headersRefExpr, new CodeExpression[] { new CodePrimitiveExpression(header) } ) ); disableOptimizedKey = true; } // Don't need to use Regex if matching . only. if (matchedString.Equals(".")) { // Simply return if the header exists. ReturnIfHeaderValueEmpty(cmm, headerValue); continue; } if (result == null) { result = GenerateVarReference(cmm, typeof(bool), _resultVarName); } GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod); cmie.Parameters.Add(headerValue); cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); //GEN: result = regexWorker.ProcessRegex(headerValue, {matchedString}); assign = new CodeAssignStatement(); assign.Left = result; assign.Right = cmie; cmm.Statements.Add(assign); //GEN: if(result == false) { //GEN: return false; //GEN: } CodeConditionStatement istatement = new CodeConditionStatement(); if(((CheckPair)bd.IdHeaderChecks[i]).NonMatch) { istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true)); } else { istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); } istatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); cmm.Statements.Add(istatement); } } if (bd.IdCapabilityChecks.Count > 0) { AddComment("Identification: check capability matches", cmm); for (int i = 0; i < bd.IdCapabilityChecks.Count; i++) { string matchedString = ((CheckPair)bd.IdCapabilityChecks[i]).MatchString; // Skip matching ".*" if (matchedString.Equals(".*")) { continue; } if (headerValue == null) { headerValue = GenerateVarReference(cmm, typeof(string), "headerValue"); } CodeAssignStatement valueAssignment = new CodeAssignStatement(); cmm.Statements.Add(valueAssignment); valueAssignment.Left = headerValue; valueAssignment.Right = (new CodeCastExpression(typeof(string), new CodeIndexerExpression( _dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(((CheckPair)bd.IdCapabilityChecks[i]).Header) } ) )); // Don't need to use Regex if matching . only. if (matchedString.Equals(".")) { continue; } if (result == null) { result = GenerateVarReference(cmm, typeof(bool), _resultVarName); } GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); //GEN: result = regexWorker.ProcessRegex((string)dictionary["xxxCapability"], "xxxRegexString"); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod); cmie.Parameters.Add(headerValue); cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); assign = new CodeAssignStatement(); assign.Left = result; assign.Right = cmie; cmm.Statements.Add(assign); //GEN: if(result == false) { //GEN: return false; //GEN: } CodeConditionStatement istatement = new CodeConditionStatement(); if (((CheckPair)bd.IdCapabilityChecks[i]).NonMatch) { istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true)); } else { istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); } istatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); cmm.Statements.Add(istatement); } } //GEN: browserCaps.DisableOptimizedCacheKey(); if (disableOptimizedKey) { CodeMethodInvokeExpression cme = new CodeMethodInvokeExpression(_browserCapsRefExpr, _disableOptimizedCacheKeyMethodName); cmm.Statements.Add(cme); } } private CodeVariableReferenceExpression GenerateVarReference(CodeMemberMethod cmm, Type varType, string varName) { //GEN: {varType} {varName}; cmm.Statements.Add(new CodeVariableDeclarationStatement(varType, varName)); return new CodeVariableReferenceExpression(varName); } //generate part of the xxxProcess method for running and storing the capture regexes private void GenerateCapturesCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) { if ((bd.CaptureHeaderChecks.Count == 0) && (bd.CaptureCapabilityChecks.Count == 0)) { return; } if(bd.CaptureHeaderChecks.Count > 0) { AddComment("Capture: header values", cmm); for(int i = 0; i < bd.CaptureHeaderChecks.Count; i++) { string matchedString = ((CheckPair)bd.CaptureHeaderChecks[i]).MatchString; if (matchedString.Equals(".*")) { continue; } GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod); if (((CheckPair)bd.CaptureHeaderChecks[i]).Header.Equals("User-Agent")) { _headers.Add(String.Empty); cmie.Parameters.Add(new CodeCastExpression(typeof(string), new CodeIndexerExpression(new CodeVariableReferenceExpression(browserCapsVariable), new CodeExpression[] { new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty") }))); } else { string header = ((CheckPair)bd.CaptureHeaderChecks[i]).Header; _headers.Add(header); //GEN: regexWorker.ProcessRegex((string)headers["xxx"], "xxxRegexString"); cmie.Parameters.Add( new CodeCastExpression(typeof(string), new CodeIndexerExpression( _headersRefExpr, new CodeExpression[] { new CodePrimitiveExpression(header) } ) ) ); } cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); cmm.Statements.Add(cmie); } } if (bd.CaptureCapabilityChecks.Count > 0) { AddComment("Capture: capability values", cmm); for(int i = 0; i < bd.CaptureCapabilityChecks.Count; i++) { string matchedString = ((CheckPair)bd.CaptureCapabilityChecks[i]).MatchString; if (matchedString.Equals(".*")) { continue; } GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); //GEN: regexWorker.ProcessRegex((string)dictionary["xxxCapability"], "xxxRegexString"); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod); cmie.Parameters.Add( new CodeCastExpression(typeof(string), new CodeIndexerExpression( _dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(((CheckPair)bd.CaptureCapabilityChecks[i]).Header) } ) ) ); cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); cmm.Statements.Add(cmie); } } } //generate part of the xxxProcess method for assigning capability values private void GenerateSetCapabilitiesCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) { //GEN: browserCaps[aaa] = "bbb"; //GEN: browserCaps[xxx] = "yyy"; NameValueCollection nvc = bd.Capabilities; CodeAssignStatement assign; AddComment("Capabilities: set capabilities", cmm); foreach (string s in nvc.Keys) { string capsString = nvc[s]; //GEN: dictionary["xxx"] = regexWorker["xxx"]; assign = new CodeAssignStatement(); assign.Left = new CodeIndexerExpression( _dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(s) } ); CodePrimitiveExpression capabilityExpr = new CodePrimitiveExpression(capsString); if (RegexWorker.RefPat.Match(capsString).Success) { GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); assign.Right = new CodeIndexerExpression( _regexWorkerRefExpr, new CodeExpression[] {capabilityExpr}); } else { assign.Right = capabilityExpr; } cmm.Statements.Add(assign); } } //generate part of the xxxProcess method for setting specific adapters for this browser internal void GenerateSetAdaptersCode(BrowserDefinition bd, CodeMemberMethod cmm) { //GEN: browserCaps.Adapters[xxxControl] = yyyAdapter; foreach (DictionaryEntry entry in bd.Adapters) { string controlString = (string)entry.Key; string adapterString = (string)entry.Value; CodePropertyReferenceExpression cpre = new CodePropertyReferenceExpression(_browserCapsRefExpr, "Adapters"); CodeIndexerExpression indexerExpression = new CodeIndexerExpression( cpre, new CodeExpression[] { new CodePrimitiveExpression(controlString) } ); CodeAssignStatement assignAdapter = new CodeAssignStatement(); assignAdapter.Left = indexerExpression; assignAdapter.Right = new CodePrimitiveExpression(adapterString); cmm.Statements.Add(assignAdapter); } //GEN: browser.HtmlTextWriter = xxxHtmlTextWriter; if(bd.HtmlTextWriterString != null) { CodeAssignStatement assignHtmlTextWriter = new CodeAssignStatement(); assignHtmlTextWriter.Left = new CodePropertyReferenceExpression(_browserCapsRefExpr, "HtmlTextWriter"); assignHtmlTextWriter.Right = new CodePrimitiveExpression(bd.HtmlTextWriterString); cmm.Statements.Add(assignHtmlTextWriter); } return; } internal void AddComment(string comment, CodeMemberMethod cmm) { cmm.Statements.Add(new CodeCommentStatement(comment)); } internal CodeStatementCollection GenerateTrackedSingleProcessCall(CodeStatementCollection stmts, BrowserDefinition bd, CodeMemberMethod cmm) { return GenerateTrackedSingleProcessCall(stmts, bd, cmm, String.Empty); } internal CodeStatementCollection GenerateTrackedSingleProcessCall(CodeStatementCollection stmts, BrowserDefinition bd, CodeMemberMethod cmm, string prefix) { //GEN: if (xProcess(headers, browserCaps)) { // } // else { // ... // } CodeMethodInvokeExpression xProcess = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), prefix + bd.Name + "Process"); xProcess.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName)); xProcess.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable)); CodeConditionStatement conditionStmt = new CodeConditionStatement(); conditionStmt.Condition = xProcess; stmts.Add(conditionStmt); return conditionStmt.FalseStatements; } internal void GenerateSingleProcessCall(BrowserDefinition bd, CodeMemberMethod cmm) { GenerateSingleProcessCall(bd, cmm, String.Empty); } //generate code to call the xxxProcess for a given browser //and store the result in a local variable internal void GenerateSingleProcessCall(BrowserDefinition bd, CodeMemberMethod cmm, string prefix) { //GEN: xProcess(headers, browserCaps); CodeMethodInvokeExpression xProcess = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), prefix + bd.Name + "Process"); xProcess.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName)); xProcess.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable)); cmm.Statements.Add(xProcess); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Web.Configuration { using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Configuration; using System.Collections; using System.Collections.Specialized; using System.IO; #if !FEATURE_PAL using System.ServiceProcess; #endif // !FEATURE_PAL using System.Reflection; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Web; using System.Web.Compilation; using System.Web.Configuration; using System.Web.Hosting; using System.Web.UI; using System.Web.Util; using System.Xml; using System.Xml.Schema; using Microsoft.CSharp; [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)] [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)] public class BrowserCapabilitiesCodeGenerator { private static readonly string _browsersDirectory; private static readonly string _publicKeyTokenFile; private static object _staticLock = new object(); private BrowserTree _browserTree; private BrowserTree _defaultTree; private BrowserDefinitionCollection _browserDefinitionCollection; internal const string browserCapsVariable = "browserCaps"; internal const string IgnoreApplicationBrowserVariableName = "ignoreApplicationBrowsers"; private const string _factoryTypeName = "BrowserCapabilitiesFactory"; private const string _headerDictionaryVarName = "_headerDictionary"; private const string _disableOptimizedCacheKeyMethodName = "DisableOptimizedCacheKey"; private const string _matchedHeadersMethodName = "PopulateMatchedHeaders"; private const string _browserElementsMethodName = "PopulateBrowserElements"; private const string _dictionaryRefName = "dictionary"; private const string _regexWorkerRefName = "regexWorker"; private const string _headersRefName = "headers"; private const string _resultVarName = "result"; private const string _processRegexMethod = "ProcessRegex"; private static readonly string _strongNameKeyFileName = browserCapsVariable + ".snk"; private static readonly string _publicKeyTokenFileName = browserCapsVariable + ".token"; private static bool _publicKeyTokenLoaded; private static string _publicKeyToken; private CodeVariableReferenceExpression _dictionaryRefExpr = new CodeVariableReferenceExpression(_dictionaryRefName); private CodeVariableReferenceExpression _regexWorkerRefExpr = new CodeVariableReferenceExpression(_regexWorkerRefName); private CodeVariableReferenceExpression _headersRefExpr = new CodeVariableReferenceExpression(_headersRefName); private CodeVariableReferenceExpression _browserCapsRefExpr = new CodeVariableReferenceExpression(browserCapsVariable); private ArrayList _browserFileList; private ArrayList _customBrowserFileLists; private ArrayList _customTreeList; private ArrayList _customTreeNames; private ArrayList _customBrowserDefinitionCollections; private CaseInsensitiveStringSet _headers; static BrowserCapabilitiesCodeGenerator() { #if !PLATFORM_UNIX // File system paths must account for UNIX _browsersDirectory = HttpRuntime.ClrInstallDirectoryInternal + "\\config\\browsers"; _publicKeyTokenFile = _browsersDirectory + "\\" + _publicKeyTokenFileName; #else // !PLATFORM_UNIX _browsersDirectory = HttpRuntime.ClrInstallDirectoryInternal + "/config/browsers"; _publicKeyTokenFile = _browsersDirectory + "/" + _publicKeyTokenFileName; #endif // !PLATFORM_UNIX } public BrowserCapabilitiesCodeGenerator() { _headers = new CaseInsensitiveStringSet(); } internal BrowserTree BrowserTree { get { return _browserTree; } } internal BrowserTree DefaultTree { get { return _defaultTree; } } internal ArrayList CustomTreeList { get { return _customTreeList; } } internal ArrayList CustomTreeNames { get { return _customTreeNames; } } internal static string BrowserCapAssemblyPublicKeyToken { get { if (_publicKeyTokenLoaded) { return _publicKeyToken; } lock (_staticLock) { if (_publicKeyTokenLoaded) { return _publicKeyToken; } _publicKeyToken = LoadPublicKeyTokenFromFile(_publicKeyTokenFile); _publicKeyTokenLoaded = true; return _publicKeyToken; } } } internal virtual bool GenerateOverrides { get { return true; } } internal virtual string TypeName { get { return _factoryTypeName; } } internal void AddFile(string filePath) { if (_browserFileList == null) _browserFileList = new ArrayList(); _browserFileList.Add(filePath); } internal void AddCustomFile(string filePath) { if (_customBrowserFileLists == null) { _customBrowserFileLists = new ArrayList(); } _customBrowserFileLists.Add(filePath); } //parse the config info and create BrowserTree //then generate code for, compile, and gac the object [SecurityPermission(SecurityAction.Demand, Unrestricted=true)] public virtual void Create() { DirectoryInfo browserDirInfo = new DirectoryInfo(_browsersDirectory); //get all the browser files and put them in the "tree" FileInfo[] browserFiles = browserDirInfo.GetFiles("*.browser"); if (browserFiles == null || browserFiles.Length == 0) { return; } foreach(FileInfo browserFile in browserFiles) { AddFile(browserFile.FullName); } // First parse the browser files. ProcessBrowserFiles(); // Then parse custom browser files. ProcessCustomBrowserFiles(); // Uninstall previously installed generated assembly. Uninstall(); //generate the source code, compile it, and gac it GenerateAssembly(); // Restart w3svc service RestartW3SVCIfNecessary(); } internal bool UninstallInternal() { // Remove existing strong name public token file if (File.Exists(_publicKeyTokenFile)) { File.Delete(_publicKeyTokenFile); } // Removing existing copy from GAC GacUtil gacutil = new GacUtil(); bool assemblyRemoved = gacutil.GacUnInstall("ASP.BrowserCapsFactory, Version=" + ThisAssembly.Version + ", Culture=neutral"); if (!assemblyRemoved) { return false; } return true; } [SecurityPermission(SecurityAction.Demand, Unrestricted = true)] public bool Uninstall() { // Restart w3svc service RestartW3SVCIfNecessary(); if (!UninstallInternal()) { return false; } // Restart w3svc service again so applications get a fresh copy. RestartW3SVCIfNecessary(); return true; } private void RestartW3SVCIfNecessary() { #if !FEATURE_PAL try { ServiceController controller = new ServiceController("W3SVC"); ServiceControllerStatus status = controller.Status; // Stop the service if it's not currently stopped or pending. if (!status.Equals(ServiceControllerStatus.Stopped) && !status.Equals(ServiceControllerStatus.StopPending) && !status.Equals(ServiceControllerStatus.StartPending)) { controller.Stop(); // Give it 5 minutes to stop controller.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 5, 0)); controller.Start(); // If the service was paused, pause it. if (status.Equals(ServiceControllerStatus.Paused) || status.Equals(ServiceControllerStatus.PausePending)) { controller.Pause(); } } } catch (Exception ex) { throw new InvalidOperationException(SR.GetString(SR.Browser_W3SVC_Failure_Helper_Text, ex)); } #endif // !FEATURE_PAL } internal void ProcessBrowserFiles() { ProcessBrowserFiles(false, String.Empty); } private string NoPathFileName(string fullPath) { int lastSlash = fullPath.LastIndexOf("\\", StringComparison.Ordinal); if(lastSlash > -1) { return fullPath.Substring(lastSlash + 1); } return fullPath; } internal virtual void ProcessBrowserNode(XmlNode node, BrowserTree browserTree) { BrowserDefinition browserInfo = null; if (node.Name == "gateway") { browserInfo = new GatewayDefinition(node); } else if (node.Name == "browser") { browserInfo = new BrowserDefinition(node); } else { Debug.Assert(node.Name == "defaultBrowser"); browserInfo = new BrowserDefinition(node, true); } BrowserDefinition oldNode = (BrowserDefinition)browserTree[browserInfo.Name]; if (oldNode != null) { if (browserInfo.IsRefID) { oldNode.MergeWithDefinition(browserInfo); } else { throw new ConfigurationErrorsException(SR.GetString(SR.Duplicate_browser_id, browserInfo.ID), node); } } else { browserTree[browserInfo.Name] = browserInfo; } } private void NormalizeAndValidateTree(BrowserTree browserTree, bool isDefaultBrowser) { NormalizeAndValidateTree(browserTree, isDefaultBrowser, false); } private void NormalizeAndValidateTree(BrowserTree browserTree, bool isDefaultBrowser, bool isCustomBrowser) { //normalize the tree foreach (DictionaryEntry entry in browserTree) { BrowserDefinition bd = (BrowserDefinition)entry.Value; string parentName = bd.ParentName; BrowserDefinition parentBrowser = null; if (IsRootNode(bd.Name)) { continue; } if (parentName.Length > 0) { parentBrowser = (BrowserDefinition)browserTree[parentName]; } if (parentBrowser != null) { if (bd.IsRefID) { if (bd is GatewayDefinition) { parentBrowser.RefGateways.Add(bd); } else { parentBrowser.RefBrowsers.Add(bd); } } else if (bd is GatewayDefinition) { parentBrowser.Gateways.Add(bd); } else { parentBrowser.Browsers.Add(bd); } } else { if (isCustomBrowser) { throw new ConfigurationErrorsException(SR.GetString(SR.Browser_parentID_Not_Found, bd.ParentID), bd.XmlNode); } else { HandleUnRecognizedParentElement(bd, isDefaultBrowser); } } } //validate the tree //loop check foreach (DictionaryEntry entry in browserTree) { BrowserDefinition bd = (BrowserDefinition)entry.Value; Hashtable loopCheck = new Hashtable(); BrowserDefinition currentBrowser = bd; string currentId = currentBrowser.Name; while (!IsRootNode(currentId)) { if (loopCheck[currentId] != null) { throw new ConfigurationErrorsException(SR.GetString(SR.Browser_Circular_Reference, currentId), currentBrowser.XmlNode); } loopCheck[currentId] = currentId; currentBrowser = (BrowserDefinition)browserTree[currentBrowser.ParentName]; //in app-level, parent can exist in machine level if (currentBrowser == null) { break; } currentId = currentBrowser.Name; } } } private void SetCustomTreeRoots(BrowserTree browserTree, int index) { foreach (DictionaryEntry entry in browserTree) { BrowserDefinition bd = (BrowserDefinition)entry.Value; if (bd.ParentName == null) { _customTreeNames[index] = bd.Name; break; } } } // Now that we support adding custom browser hierarchies, root nodes other than Default are permitted. private bool IsRootNode(string nodeName) { if (String.Compare(nodeName, "Default", StringComparison.OrdinalIgnoreCase) == 0) return true; foreach (string treeRootName in _customTreeNames) { if (String.Compare(nodeName, treeRootName, StringComparison.OrdinalIgnoreCase) == 0) { return true; } } return false; } protected void ProcessBrowserFiles(bool useVirtualPath, string virtualDir) { _browserTree = new BrowserTree(); _defaultTree = new BrowserTree(); _customTreeNames = new ArrayList(); if (_browserFileList == null) { _browserFileList = new ArrayList(); } _browserFileList.Sort(); //#if OPTIMIZE_FOR_DESKTOP_BROWSER string mozillaFile = null; string ieFile = null; string operaFile = null; // DevDivBugs 180962 // IE, Mozilla and Opera are first-class browsers. Their User-Agent profiles need to be compared to the UA profile // of the HTTP request before other browsers. We put them to the head of the list so that the generated browser capabilities // code will try to match them before other browsers. foreach (String filePath in _browserFileList) { if (filePath.EndsWith("ie.browser", StringComparison.OrdinalIgnoreCase)) { ieFile = filePath; } else if (filePath.EndsWith("mozilla.browser", StringComparison.OrdinalIgnoreCase)) { mozillaFile = filePath; } else if (filePath.EndsWith("opera.browser", StringComparison.OrdinalIgnoreCase)) { operaFile = filePath; break; } } if (ieFile != null) { _browserFileList.Remove(ieFile); _browserFileList.Insert(0, ieFile); } if (mozillaFile != null) { _browserFileList.Remove(mozillaFile); _browserFileList.Insert(1, mozillaFile); } if (operaFile != null) { _browserFileList.Remove(operaFile); _browserFileList.Insert(2, operaFile); } //#endif foreach (string fileName in _browserFileList) { XmlDocument doc = new ConfigXmlDocument(); try { doc.Load(fileName); XmlNode rootNode = doc.DocumentElement; if(rootNode.Name != "browsers") { if(useVirtualPath) { throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, 1); } else { throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, fileName, null /*sourceCode*/, 1); } } foreach (XmlNode node in rootNode.ChildNodes) { if (node.NodeType != XmlNodeType.Element) continue; if (node.Name == "browser" || node.Name == "gateway") { ProcessBrowserNode(node, _browserTree); } else if (node.Name == "defaultBrowser") { ProcessBrowserNode(node, _defaultTree); } else { HandlerBase.ThrowUnrecognizedElement(node); } } } catch (XmlException e) { if(useVirtualPath) { throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber); } else { throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); } } catch (XmlSchemaException e) { if(useVirtualPath) { string noPathFileName = String.Empty; int lastSlash = fileName.LastIndexOf("\\", StringComparison.Ordinal); if(lastSlash > -1) { noPathFileName = fileName.Substring(lastSlash); } throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber); } else { throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); } } } NormalizeAndValidateTree(_browserTree, false); NormalizeAndValidateTree(_defaultTree, true); BrowserDefinition defaultBrowser = (BrowserDefinition)_browserTree["Default"]; if (defaultBrowser != null) { AddBrowserToCollectionRecursive(defaultBrowser, 0); } } internal void ProcessCustomBrowserFiles() { ProcessCustomBrowserFiles(false, String.Empty); } internal void ProcessCustomBrowserFiles(bool useVirtualPath, string virtualDir) { //get all custom browser files and put them in the "tree" DirectoryInfo browserDirInfo = null; DirectoryInfo[] browserSubDirectories = null; ArrayList customBrowserFileNames; _customTreeList = new ArrayList(); _customBrowserFileLists = new ArrayList(); _customBrowserDefinitionCollections = new ArrayList(); /* Machine Level Custom Browsers */ if (useVirtualPath == false) { browserDirInfo = new DirectoryInfo(_browsersDirectory); } /* Application Level Custom Browsers */ else { browserDirInfo = new DirectoryInfo(HostingEnvironment.MapPathInternal(virtualDir)); } browserSubDirectories = browserDirInfo.GetDirectories(); for (int i = 0; i < browserSubDirectories.Length; i++) { /* Recursively Into Subdirectories */ FileInfo[] browserFiles = browserSubDirectories[i].GetFiles("*.browser", SearchOption.AllDirectories); if (browserFiles == null || browserFiles.Length == 0) { continue; } BrowserTree customTree = new BrowserTree(); _customTreeList.Add(customTree); _customTreeNames.Add(browserSubDirectories[i].Name); customBrowserFileNames = new ArrayList(); foreach (FileInfo browserFile in browserFiles) { customBrowserFileNames.Add(browserFile.FullName); } _customBrowserFileLists.Add(customBrowserFileNames); } for (int i = 0; i < _customBrowserFileLists.Count; i++) { ArrayList fileNames = (ArrayList)_customBrowserFileLists[i]; foreach (string fileName in fileNames) { XmlDocument doc = new ConfigXmlDocument(); try { doc.Load(fileName); XmlNode rootNode = doc.DocumentElement; if (rootNode.Name != "browsers") { if (useVirtualPath) { throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, 1); } else { throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, fileName, null /*sourceCode*/, 1); } } foreach (XmlNode node in rootNode.ChildNodes) { if (node.NodeType != XmlNodeType.Element) { continue; } if (node.Name == "browser" || node.Name == "gateway") { ProcessBrowserNode(node, (BrowserTree)_customTreeList[i]); } else { HandlerBase.ThrowUnrecognizedElement(node); } } } catch (XmlException e) { if (useVirtualPath) { throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber); } else { throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); } } catch (XmlSchemaException e) { if (useVirtualPath) { string noPathFileName = String.Empty; int lastSlash = fileName.LastIndexOf("\\", StringComparison.Ordinal); if (lastSlash > -1) { noPathFileName = fileName.Substring(lastSlash); } throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber); } else { throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); } } } SetCustomTreeRoots((BrowserTree)_customTreeList[i], i); NormalizeAndValidateTree((BrowserTree)_customTreeList[i], false, true); _customBrowserDefinitionCollections.Add(new BrowserDefinitionCollection()); AddCustomBrowserToCollectionRecursive((BrowserDefinition)(((BrowserTree)_customTreeList[i])[_customTreeNames[i]]), 0, i); } } internal void AddCustomBrowserToCollectionRecursive(BrowserDefinition bd, int depth, int index) { if(_customBrowserDefinitionCollections[index] == null) { _customBrowserDefinitionCollections[index] = new BrowserDefinitionCollection(); } bd.Depth = depth; bd.IsDeviceNode = true; ((BrowserDefinitionCollection)_customBrowserDefinitionCollections[index]).Add(bd); foreach (BrowserDefinition childBrowser in bd.Browsers) { AddCustomBrowserToCollectionRecursive(childBrowser, depth + 1, index); } } internal void AddBrowserToCollectionRecursive(BrowserDefinition bd, int depth) { if (_browserDefinitionCollection == null) { _browserDefinitionCollection = new BrowserDefinitionCollection(); } bd.Depth = depth; bd.IsDeviceNode = true; _browserDefinitionCollection.Add(bd); foreach(BrowserDefinition childBrowser in bd.Browsers) { AddBrowserToCollectionRecursive(childBrowser, depth + 1); } } internal virtual void HandleUnRecognizedParentElement(BrowserDefinition bd, bool isDefault) { throw new ConfigurationErrorsException(SR.GetString(SR.Browser_parentID_Not_Found, bd.ParentID), bd.XmlNode); } //generate the code from the parsed BrowserDefinitionTree //compile it, and install it in the gac private void GenerateAssembly() { Debug.Assert(_browserTree != null); BrowserDefinition root = (BrowserDefinition)_browserTree["Default"]; BrowserDefinition defaultRoot = (BrowserDefinition)_defaultTree["Default"]; ArrayList customTreeRoots = new ArrayList(); for (int i = 0; i < _customTreeNames.Count; i++) { customTreeRoots.Add((BrowserDefinition)(((BrowserTree)_customTreeList[i])[_customTreeNames[i]])); } //create a CodeCompileUnit //add a CodeNamespace object to the CodeCompileUnit //add a CodeTypeDeclaration to the CodeNamespace //add all the members of the type/class to the CodeTypeDeclaration //use a CodeGenerator to generate code from the CodeCompileUnit //a CodeDomProvider can provide a CodeGenerator //translate the BrowserDefinition tree to code CSharpCodeProvider cscp = new CSharpCodeProvider(); // namespace System.Web.BrowserCapsFactory CodeCompileUnit ccu = new CodeCompileUnit(); //add strong-name key pair for CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( "System.Reflection.AssemblyKeyFile", new CodeAttributeArgument[] { new CodeAttributeArgument(new CodePrimitiveExpression(_strongNameKeyFileName))}); CodeAttributeDeclaration aptca = new CodeAttributeDeclaration( "System.Security.AllowPartiallyTrustedCallers"); ccu.AssemblyCustomAttributes.Add(aptca); ccu.AssemblyCustomAttributes.Add(declaration); //add version number for it so it can distinguished in future versions declaration = new CodeAttributeDeclaration( "System.Reflection.AssemblyVersion", new CodeAttributeArgument[] { new CodeAttributeArgument(new CodePrimitiveExpression(ThisAssembly.Version))}); ccu.AssemblyCustomAttributes.Add(declaration); CodeNamespace cnamespace = new CodeNamespace("ASP"); //GEN: using System; cnamespace.Imports.Add(new CodeNamespaceImport("System")); //GEN: using System.Web; cnamespace.Imports.Add(new CodeNamespaceImport("System.Web")); //GEN: using System.Web.Configuration; cnamespace.Imports.Add(new CodeNamespaceImport("System.Web.Configuration")); //GEN: using System.Reflection; cnamespace.Imports.Add(new CodeNamespaceImport("System.Reflection")); //GEN: class BrowserCapabilitiesFactory ccu.Namespaces.Add(cnamespace); CodeTypeDeclaration factoryType = new CodeTypeDeclaration("BrowserCapabilitiesFactory"); factoryType.Attributes = MemberAttributes.Private; factoryType.IsClass = true; factoryType.Name = TypeName; factoryType.BaseTypes.Add(new CodeTypeReference("System.Web.Configuration.BrowserCapabilitiesFactoryBase")); cnamespace.Types.Add(factoryType); //GEN: protected override object ConfigureBrowserCapabilities(NameValueCollection headers, HttpBrowserCapabilities browserCaps) CodeMemberMethod method = new CodeMemberMethod(); method.Attributes = MemberAttributes.Override | MemberAttributes.Public; method.ReturnType = new CodeTypeReference(typeof(void)); method.Name = "ConfigureBrowserCapabilities"; CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName); method.Parameters.Add(cpde); cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable); method.Parameters.Add(cpde); factoryType.Members.Add(method); GenerateSingleProcessCall(root, method); for (int i = 0; i < customTreeRoots.Count; i++) { GenerateSingleProcessCall((BrowserDefinition)customTreeRoots[i], method); } //GEN: if(this.IsBrowserUnknown(browserCaps) == false) return; CodeConditionStatement istatement = new CodeConditionStatement(); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "IsBrowserUnknown"); cmie.Parameters.Add(_browserCapsRefExpr); istatement.Condition = new CodeBinaryOperatorExpression(cmie, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); istatement.TrueStatements.Add(new CodeMethodReturnStatement()); method.Statements.Add(istatement); if(defaultRoot != null) { GenerateSingleProcessCall(defaultRoot, method, "Default"); } for (int i = 0; i < customTreeRoots.Count; i++) { foreach (DictionaryEntry entry in (BrowserTree)_customTreeList[i]) { BrowserDefinition bd = entry.Value as BrowserDefinition; Debug.Assert(bd != null); GenerateProcessMethod(bd, factoryType); } } //GenerateCallsToProcessMethods(root, method); foreach (DictionaryEntry entry in _browserTree) { BrowserDefinition bd = entry.Value as BrowserDefinition; Debug.Assert(bd != null); GenerateProcessMethod(bd, factoryType); } foreach (DictionaryEntry entry in _defaultTree) { BrowserDefinition bd = entry.Value as BrowserDefinition; Debug.Assert(bd != null); GenerateProcessMethod(bd, factoryType, "Default"); } GenerateOverrideMatchedHeaders(factoryType); GenerateOverrideBrowserElements(factoryType); // TextWriter twriter = new StreamWriter(new FileStream(_browsersDirectory + "\\BrowserCapsFactory.cs", FileMode.Create)); try { cscp.GenerateCodeFromCompileUnit(ccu, twriter, null); } finally { if(twriter != null) twriter.Close(); } CompilationSection compConfig = RuntimeConfig.GetAppConfig().Compilation; bool debug = compConfig.Debug; #if !PLATFORM_UNIX // File system paths must account for UNIX string strongNameFile = _browsersDirectory + "\\" + _strongNameKeyFileName; #else // !PLATFORM_UNIX string strongNameFile = _browsersDirectory + "/" + _strongNameKeyFileName; #endif // !PLATFORM_UNIX // Generate strong name file StrongNameUtility.GenerateStrongNameFile(strongNameFile); // string[] referencedAssemblies = new string[2] { "System.dll", "System.Web.dll" }; CompilerParameters compilerParameters = new CompilerParameters(referencedAssemblies, "ASP.BrowserCapsFactory", debug /* includeDebugInformation */ ); compilerParameters.GenerateInMemory = false; compilerParameters.OutputAssembly = _browsersDirectory + "\\ASP.BrowserCapsFactory.dll"; CompilerResults results = null; try { results = cscp.CompileAssemblyFromFile(compilerParameters, _browsersDirectory + "\\BrowserCapsFactory.cs"); } finally { if (File.Exists(strongNameFile)) { File.Delete(strongNameFile); } } if (results.NativeCompilerReturnValue != 0 || results.Errors.HasErrors) { foreach (CompilerError error in results.Errors) { if (!error.IsWarning) { throw new HttpCompileException(error.ErrorText); } } throw new HttpCompileException(SR.GetString(SR.Browser_compile_error)); } Assembly resultAssembly = results.CompiledAssembly; GacUtil gacutil = new GacUtil(); gacutil.GacInstall(resultAssembly.Location); SavePublicKeyTokenFile(_publicKeyTokenFile, resultAssembly.GetName().GetPublicKeyToken()); } private void SavePublicKeyTokenFile(string filename, byte[] publicKeyToken) { using (FileStream pktStream = new FileStream(filename, FileMode.Create, FileAccess.Write)) { using (StreamWriter pktWriter = new StreamWriter(pktStream)) { foreach (byte b in publicKeyToken) { pktWriter.Write("{0:X2}", b); } } } } private static string LoadPublicKeyTokenFromFile(string filename) { IStackWalk fileReadAccess = InternalSecurityPermissions.FileReadAccess(filename); Debug.Assert(fileReadAccess != null); fileReadAccess.Assert(); if (!File.Exists(filename)) { return null; } try { using (FileStream pktStream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { using (StreamReader pktReader = new StreamReader(pktStream)) { return pktReader.ReadLine(); } } } catch (IOException) { if (HttpRuntime.HasFilePermission(filename)) { throw; } // Don't throw exception if we don't have permission to the file. return null; } finally { CodeAccessPermission.RevertAssert(); } } internal void GenerateOverrideBrowserElements(CodeTypeDeclaration typeDeclaration) { // Don't generate the property if there's nothing to override. if (_browserDefinitionCollection == null) { return; } // GEN: // protected override void PopulateBrowserElements(IDictionary dictionary) { // dictionary["Default"] = new Triplet(null, "default description", 0 /*depth_of_node */); // dictionary["Up"] = new Triplet("Default", "up Description", 1 /*depth_of_node */); // } CodeMemberMethod method = new CodeMemberMethod(); method.Name = _browserElementsMethodName; method.Attributes = MemberAttributes.Override | MemberAttributes.Family; method.ReturnType = new CodeTypeReference(typeof(void)); CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IDictionary)), _dictionaryRefName); method.Parameters.Add(parameter); typeDeclaration.Members.Add(method); CodeMethodReferenceExpression baseMethod = new CodeMethodReferenceExpression(new CodeBaseReferenceExpression(), _browserElementsMethodName); CodeMethodInvokeExpression baseInvoke = new CodeMethodInvokeExpression(baseMethod, new CodeExpression[] { _dictionaryRefExpr }); method.Statements.Add(baseInvoke); foreach(BrowserDefinition bd in _browserDefinitionCollection) { if (!bd.IsDeviceNode) continue; Debug.Assert(!(bd is GatewayDefinition)); CodeAssignStatement cas = new CodeAssignStatement(); cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(bd.ID) }); cas.Right = new CodeObjectCreateExpression(typeof(Triplet), new CodeExpression[] { new CodePrimitiveExpression(bd.ParentName), new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty"), new CodePrimitiveExpression(bd.Depth)}); method.Statements.Add(cas); } for (int i = 0; i < _customTreeNames.Count; i++) { foreach (BrowserDefinition bd in (BrowserDefinitionCollection)_customBrowserDefinitionCollections[i]) { if (!bd.IsDeviceNode) continue; Debug.Assert(!(bd is GatewayDefinition)); CodeAssignStatement cas = new CodeAssignStatement(); cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(bd.ID) }); cas.Right = new CodeObjectCreateExpression(typeof(Triplet), new CodeExpression[] { new CodePrimitiveExpression(bd.ParentName), new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty"), new CodePrimitiveExpression(bd.Depth)}); method.Statements.Add(cas); } } } internal void GenerateOverrideMatchedHeaders(CodeTypeDeclaration typeDeclaration) { // GEN: // protected override void PopulateMatchedHeaders(IDictionary dictionary) { // base.PopulateMatchedHeaders(dictionary); // // dictionary["header0"] = null; // dictionary["header1"] = null; // } CodeMemberMethod method = new CodeMemberMethod(); method.Name = _matchedHeadersMethodName; method.Attributes = MemberAttributes.Override | MemberAttributes.Family; method.ReturnType = new CodeTypeReference(typeof(void)); CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IDictionary)), _dictionaryRefName); method.Parameters.Add(parameter); typeDeclaration.Members.Add(method); CodeMethodReferenceExpression baseMethod = new CodeMethodReferenceExpression(new CodeBaseReferenceExpression(), _matchedHeadersMethodName); CodeMethodInvokeExpression baseInvoke = new CodeMethodInvokeExpression(baseMethod, new CodeExpression[] { _dictionaryRefExpr }); method.Statements.Add(baseInvoke); foreach(String header in _headers) { CodeAssignStatement cas = new CodeAssignStatement(); cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(header) }); cas.Right = new CodePrimitiveExpression(null); method.Statements.Add(cas); } } internal void GenerateProcessMethod(BrowserDefinition bd, CodeTypeDeclaration ctd) { GenerateProcessMethod(bd, ctd, String.Empty); } //generate the xxxProcess method for an individual BrowserDefinition internal void GenerateProcessMethod(BrowserDefinition bd, CodeTypeDeclaration ctd, string prefix) { //GEN: internal bool XxxProcess(NameValueCollection headers, HttpBrowserCapabilities browserCaps) CodeMemberMethod cmm = new CodeMemberMethod(); cmm.Name = prefix + bd.Name + "Process"; cmm.ReturnType = new CodeTypeReference(typeof(bool)); cmm.Attributes = MemberAttributes.Private; CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName); cmm.Parameters.Add(cpde); cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable); cmm.Parameters.Add(cpde); bool regexWorkerGenerated = false; GenerateIdentificationCode(bd, cmm, ref regexWorkerGenerated); GenerateCapturesCode(bd, cmm, ref regexWorkerGenerated); GenerateSetCapabilitiesCode(bd, cmm, ref regexWorkerGenerated); GenerateSetAdaptersCode(bd, cmm); // Only add the browser node to the browser collection if it represents a device. if (bd.IsDeviceNode) { Debug.Assert(!(bd is GatewayDefinition)); //GEN: browserCaps.AddBrowser("xxx"); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression(browserCapsVariable), "AddBrowser"); cmie.Parameters.Add(new CodePrimitiveExpression(bd.ID)); cmm.Statements.Add(cmie); } // Generate ref gateway elements foreach (BrowserDefinition b in bd.RefGateways) { AddComment("ref gateways, parent=" + bd.ID, cmm); GenerateSingleProcessCall(b, cmm); } if ((GenerateOverrides) && (prefix.Length == 0)) { //Gen: protected virtual void XxxProcessGateways(NameValueCollection headers, HttpBrowserCapabilities browserCaps) ; string methodName = prefix + bd.Name + "ProcessGateways"; GenerateChildProcessMethod(methodName, ctd, false); //Gen: XxxProcessGateways(headers, browserCaps) ; GenerateChildProcessInvokeExpression(methodName, cmm, false); } foreach(BrowserDefinition b in bd.Gateways) { AddComment("gateway, parent=" + bd.ID, cmm); GenerateSingleProcessCall(b, cmm); } if (GenerateOverrides) { //GEN: bool ignoreApplicationBrowsers = true | false; //bd.Browsers.Count != 0 CodeVariableDeclarationStatement cvds = new CodeVariableDeclarationStatement(typeof(bool), IgnoreApplicationBrowserVariableName, new CodePrimitiveExpression(bd.Browsers.Count != 0)); cmm.Statements.Add(cvds); } if (bd.Browsers.Count > 0) { CodeStatementCollection statements = cmm.Statements; AddComment("browser, parent=" + bd.ID, cmm); foreach (BrowserDefinition b in bd.Browsers) { statements = GenerateTrackedSingleProcessCall(statements, b, cmm, prefix); } if (GenerateOverrides) { //GEN: ignoreApplicationBrowsers = false; CodeAssignStatement codeAssignStmt = new CodeAssignStatement(); codeAssignStmt.Left = new CodeVariableReferenceExpression(IgnoreApplicationBrowserVariableName); codeAssignStmt.Right = new CodePrimitiveExpression(false); statements.Add(codeAssignStmt); } } // Generate ref browser foreach (BrowserDefinition b in bd.RefBrowsers) { AddComment("ref browsers, parent=" + bd.ID, cmm); if (b.IsDefaultBrowser) { GenerateSingleProcessCall(b, cmm, "Default"); } else { GenerateSingleProcessCall(b, cmm); } } if (GenerateOverrides) { //Gen: protected virtual void XxxProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps) ; string methodName = prefix + bd.Name + "ProcessBrowsers"; GenerateChildProcessMethod(methodName, ctd, true); //Gen: XxxProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps); GenerateChildProcessInvokeExpression(methodName, cmm, true); } //GEN: return true; CodeMethodReturnStatement cmrs = new CodeMethodReturnStatement(new CodePrimitiveExpression(true)); cmm.Statements.Add(cmrs); ctd.Members.Add(cmm); } private void GenerateChildProcessInvokeExpression(string methodName, CodeMemberMethod cmm, bool generateTracker) { //Gen: XxxProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps) ; CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), methodName); if (generateTracker) { expr.Parameters.Add(new CodeVariableReferenceExpression(IgnoreApplicationBrowserVariableName)); } expr.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName)); expr.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable)); cmm.Statements.Add(expr); } private void GenerateChildProcessMethod(string methodName, CodeTypeDeclaration ctd, bool generateTracker) { //Gen: protected virtual void XxxProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps) ; CodeMemberMethod cmm= new CodeMemberMethod(); cmm.Name = methodName; cmm.ReturnType = new CodeTypeReference(typeof(void)); cmm.Attributes = MemberAttributes.Family; CodeParameterDeclarationExpression cpde = null; if (generateTracker) { cpde = new CodeParameterDeclarationExpression(typeof(bool), IgnoreApplicationBrowserVariableName); cmm.Parameters.Add(cpde); } cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName); cmm.Parameters.Add(cpde); cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable); cmm.Parameters.Add(cpde); ctd.Members.Add(cmm); } private void GenerateRegexWorkerIfNecessary(CodeMemberMethod cmm, ref bool regexWorkerGenerated) { if (regexWorkerGenerated) { return; } regexWorkerGenerated = true; //GEN: RegexWorker regexWorker; cmm.Statements.Add(new CodeVariableDeclarationStatement("RegexWorker", _regexWorkerRefName)); //GEN: regexWorker = new RegexWorker(browserCaps); cmm.Statements.Add(new CodeAssignStatement(_regexWorkerRefExpr, new CodeObjectCreateExpression("RegexWorker", _browserCapsRefExpr))); } private void ReturnIfHeaderValueEmpty(CodeMemberMethod cmm, CodeVariableReferenceExpression varExpr) { // GEN: if(String.IsNullOrEmpty(varExpr)) { // GEN: return false; // GEN: } CodeConditionStatement emptyCheckStmt = new CodeConditionStatement(); CodeMethodReferenceExpression emptyCheckMethod = new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "IsNullOrEmpty"); CodeMethodInvokeExpression emptyCheckExpr = new CodeMethodInvokeExpression(emptyCheckMethod, varExpr); emptyCheckStmt.Condition = emptyCheckExpr; emptyCheckStmt.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); cmm.Statements.Add(emptyCheckStmt); } //generate part of the xxxProcess method for handling determining if the requesting //browser meets the regexes for this browser private void GenerateIdentificationCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) { //GEN: IDictionary dictionary; cmm.Statements.Add(new CodeVariableDeclarationStatement(typeof(IDictionary), _dictionaryRefName)); //GEN: dictionary = browserCaps.Capabilities; CodeAssignStatement assign = new CodeAssignStatement( _dictionaryRefExpr, new CodePropertyReferenceExpression(_browserCapsRefExpr, "Capabilities") ); cmm.Statements.Add(assign); bool disableOptimizedKey = false; CodeVariableReferenceExpression result = null; CodeVariableReferenceExpression headerValue = null; if(bd.IdHeaderChecks.Count > 0) { AddComment("Identification: check header matches", cmm); for (int i = 0; i < bd.IdHeaderChecks.Count; i++) { string matchedString = ((CheckPair)bd.IdHeaderChecks[i]).MatchString; // Skip matching ".*" if (matchedString.Equals(".*")) { continue; } if (headerValue == null) { headerValue = GenerateVarReference(cmm, typeof(string), "headerValue"); } CodeAssignStatement valueAssignment = new CodeAssignStatement(); cmm.Statements.Add(valueAssignment); valueAssignment.Left = headerValue; if (((CheckPair)bd.IdHeaderChecks[i]).Header.Equals("User-Agent")) { _headers.Add(String.Empty); // GEN: headerValue = ((string)(browserCaps[String.Empty])); valueAssignment.Right = new CodeCastExpression(typeof(string), new CodeIndexerExpression( new CodeVariableReferenceExpression(browserCapsVariable), new CodeExpression[] { new CodePropertyReferenceExpression( new CodeTypeReferenceExpression(typeof(String)), "Empty") })); } else { string header = ((CheckPair)bd.IdHeaderChecks[i]).Header; _headers.Add(header); //GEN: headerValue = ((String)headers["xxx"]); valueAssignment.Right = new CodeCastExpression(typeof(string), new CodeIndexerExpression( _headersRefExpr, new CodeExpression[] { new CodePrimitiveExpression(header) } ) ); disableOptimizedKey = true; } // Don't need to use Regex if matching . only. if (matchedString.Equals(".")) { // Simply return if the header exists. ReturnIfHeaderValueEmpty(cmm, headerValue); continue; } if (result == null) { result = GenerateVarReference(cmm, typeof(bool), _resultVarName); } GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod); cmie.Parameters.Add(headerValue); cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); //GEN: result = regexWorker.ProcessRegex(headerValue, {matchedString}); assign = new CodeAssignStatement(); assign.Left = result; assign.Right = cmie; cmm.Statements.Add(assign); //GEN: if(result == false) { //GEN: return false; //GEN: } CodeConditionStatement istatement = new CodeConditionStatement(); if(((CheckPair)bd.IdHeaderChecks[i]).NonMatch) { istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true)); } else { istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); } istatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); cmm.Statements.Add(istatement); } } if (bd.IdCapabilityChecks.Count > 0) { AddComment("Identification: check capability matches", cmm); for (int i = 0; i < bd.IdCapabilityChecks.Count; i++) { string matchedString = ((CheckPair)bd.IdCapabilityChecks[i]).MatchString; // Skip matching ".*" if (matchedString.Equals(".*")) { continue; } if (headerValue == null) { headerValue = GenerateVarReference(cmm, typeof(string), "headerValue"); } CodeAssignStatement valueAssignment = new CodeAssignStatement(); cmm.Statements.Add(valueAssignment); valueAssignment.Left = headerValue; valueAssignment.Right = (new CodeCastExpression(typeof(string), new CodeIndexerExpression( _dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(((CheckPair)bd.IdCapabilityChecks[i]).Header) } ) )); // Don't need to use Regex if matching . only. if (matchedString.Equals(".")) { continue; } if (result == null) { result = GenerateVarReference(cmm, typeof(bool), _resultVarName); } GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); //GEN: result = regexWorker.ProcessRegex((string)dictionary["xxxCapability"], "xxxRegexString"); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod); cmie.Parameters.Add(headerValue); cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); assign = new CodeAssignStatement(); assign.Left = result; assign.Right = cmie; cmm.Statements.Add(assign); //GEN: if(result == false) { //GEN: return false; //GEN: } CodeConditionStatement istatement = new CodeConditionStatement(); if (((CheckPair)bd.IdCapabilityChecks[i]).NonMatch) { istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true)); } else { istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); } istatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); cmm.Statements.Add(istatement); } } //GEN: browserCaps.DisableOptimizedCacheKey(); if (disableOptimizedKey) { CodeMethodInvokeExpression cme = new CodeMethodInvokeExpression(_browserCapsRefExpr, _disableOptimizedCacheKeyMethodName); cmm.Statements.Add(cme); } } private CodeVariableReferenceExpression GenerateVarReference(CodeMemberMethod cmm, Type varType, string varName) { //GEN: {varType} {varName}; cmm.Statements.Add(new CodeVariableDeclarationStatement(varType, varName)); return new CodeVariableReferenceExpression(varName); } //generate part of the xxxProcess method for running and storing the capture regexes private void GenerateCapturesCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) { if ((bd.CaptureHeaderChecks.Count == 0) && (bd.CaptureCapabilityChecks.Count == 0)) { return; } if(bd.CaptureHeaderChecks.Count > 0) { AddComment("Capture: header values", cmm); for(int i = 0; i < bd.CaptureHeaderChecks.Count; i++) { string matchedString = ((CheckPair)bd.CaptureHeaderChecks[i]).MatchString; if (matchedString.Equals(".*")) { continue; } GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod); if (((CheckPair)bd.CaptureHeaderChecks[i]).Header.Equals("User-Agent")) { _headers.Add(String.Empty); cmie.Parameters.Add(new CodeCastExpression(typeof(string), new CodeIndexerExpression(new CodeVariableReferenceExpression(browserCapsVariable), new CodeExpression[] { new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty") }))); } else { string header = ((CheckPair)bd.CaptureHeaderChecks[i]).Header; _headers.Add(header); //GEN: regexWorker.ProcessRegex((string)headers["xxx"], "xxxRegexString"); cmie.Parameters.Add( new CodeCastExpression(typeof(string), new CodeIndexerExpression( _headersRefExpr, new CodeExpression[] { new CodePrimitiveExpression(header) } ) ) ); } cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); cmm.Statements.Add(cmie); } } if (bd.CaptureCapabilityChecks.Count > 0) { AddComment("Capture: capability values", cmm); for(int i = 0; i < bd.CaptureCapabilityChecks.Count; i++) { string matchedString = ((CheckPair)bd.CaptureCapabilityChecks[i]).MatchString; if (matchedString.Equals(".*")) { continue; } GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); //GEN: regexWorker.ProcessRegex((string)dictionary["xxxCapability"], "xxxRegexString"); CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod); cmie.Parameters.Add( new CodeCastExpression(typeof(string), new CodeIndexerExpression( _dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(((CheckPair)bd.CaptureCapabilityChecks[i]).Header) } ) ) ); cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); cmm.Statements.Add(cmie); } } } //generate part of the xxxProcess method for assigning capability values private void GenerateSetCapabilitiesCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) { //GEN: browserCaps[aaa] = "bbb"; //GEN: browserCaps[xxx] = "yyy"; NameValueCollection nvc = bd.Capabilities; CodeAssignStatement assign; AddComment("Capabilities: set capabilities", cmm); foreach (string s in nvc.Keys) { string capsString = nvc[s]; //GEN: dictionary["xxx"] = regexWorker["xxx"]; assign = new CodeAssignStatement(); assign.Left = new CodeIndexerExpression( _dictionaryRefExpr, new CodeExpression[] { new CodePrimitiveExpression(s) } ); CodePrimitiveExpression capabilityExpr = new CodePrimitiveExpression(capsString); if (RegexWorker.RefPat.Match(capsString).Success) { GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); assign.Right = new CodeIndexerExpression( _regexWorkerRefExpr, new CodeExpression[] {capabilityExpr}); } else { assign.Right = capabilityExpr; } cmm.Statements.Add(assign); } } //generate part of the xxxProcess method for setting specific adapters for this browser internal void GenerateSetAdaptersCode(BrowserDefinition bd, CodeMemberMethod cmm) { //GEN: browserCaps.Adapters[xxxControl] = yyyAdapter; foreach (DictionaryEntry entry in bd.Adapters) { string controlString = (string)entry.Key; string adapterString = (string)entry.Value; CodePropertyReferenceExpression cpre = new CodePropertyReferenceExpression(_browserCapsRefExpr, "Adapters"); CodeIndexerExpression indexerExpression = new CodeIndexerExpression( cpre, new CodeExpression[] { new CodePrimitiveExpression(controlString) } ); CodeAssignStatement assignAdapter = new CodeAssignStatement(); assignAdapter.Left = indexerExpression; assignAdapter.Right = new CodePrimitiveExpression(adapterString); cmm.Statements.Add(assignAdapter); } //GEN: browser.HtmlTextWriter = xxxHtmlTextWriter; if(bd.HtmlTextWriterString != null) { CodeAssignStatement assignHtmlTextWriter = new CodeAssignStatement(); assignHtmlTextWriter.Left = new CodePropertyReferenceExpression(_browserCapsRefExpr, "HtmlTextWriter"); assignHtmlTextWriter.Right = new CodePrimitiveExpression(bd.HtmlTextWriterString); cmm.Statements.Add(assignHtmlTextWriter); } return; } internal void AddComment(string comment, CodeMemberMethod cmm) { cmm.Statements.Add(new CodeCommentStatement(comment)); } internal CodeStatementCollection GenerateTrackedSingleProcessCall(CodeStatementCollection stmts, BrowserDefinition bd, CodeMemberMethod cmm) { return GenerateTrackedSingleProcessCall(stmts, bd, cmm, String.Empty); } internal CodeStatementCollection GenerateTrackedSingleProcessCall(CodeStatementCollection stmts, BrowserDefinition bd, CodeMemberMethod cmm, string prefix) { //GEN: if (xProcess(headers, browserCaps)) { // } // else { // ... // } CodeMethodInvokeExpression xProcess = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), prefix + bd.Name + "Process"); xProcess.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName)); xProcess.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable)); CodeConditionStatement conditionStmt = new CodeConditionStatement(); conditionStmt.Condition = xProcess; stmts.Add(conditionStmt); return conditionStmt.FalseStatements; } internal void GenerateSingleProcessCall(BrowserDefinition bd, CodeMemberMethod cmm) { GenerateSingleProcessCall(bd, cmm, String.Empty); } //generate code to call the xxxProcess for a given browser //and store the result in a local variable internal void GenerateSingleProcessCall(BrowserDefinition bd, CodeMemberMethod cmm, string prefix) { //GEN: xProcess(headers, browserCaps); CodeMethodInvokeExpression xProcess = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), prefix + bd.Name + "Process"); xProcess.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName)); xProcess.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable)); cmm.Statements.Add(xProcess); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- PropertyPathConverter.cs
- BigInt.cs
- Compilation.cs
- ListViewItemSelectionChangedEvent.cs
- LineMetrics.cs
- DataGrid.cs
- IndependentlyAnimatedPropertyMetadata.cs
- PathGeometry.cs
- Wildcard.cs
- GeometryHitTestResult.cs
- FilterQuery.cs
- CodeBlockBuilder.cs
- WindowVisualStateTracker.cs
- TimerElapsedEvenArgs.cs
- PolicyLevel.cs
- WebSysDefaultValueAttribute.cs
- SqlTypeSystemProvider.cs
- FamilyTypeface.cs
- OpenTypeCommon.cs
- PeerOutputChannel.cs
- DebugView.cs
- ObjectStateFormatter.cs
- InputLanguageProfileNotifySink.cs
- CodeIdentifiers.cs
- XmlNavigatorFilter.cs
- DeferrableContentConverter.cs
- AdornerDecorator.cs
- XmlUtil.cs
- ZipIOBlockManager.cs
- UserPersonalizationStateInfo.cs
- ApplicationSecurityManager.cs
- DecoderNLS.cs
- _DisconnectOverlappedAsyncResult.cs
- EntityProviderFactory.cs
- SineEase.cs
- AlphabeticalEnumConverter.cs
- XmlSecureResolver.cs
- ClaimTypeElement.cs
- DataQuery.cs
- AnchorEditor.cs
- HttpCapabilitiesEvaluator.cs
- ContractNamespaceAttribute.cs
- IndexedGlyphRun.cs
- Stream.cs
- LateBoundBitmapDecoder.cs
- ComplexTypeEmitter.cs
- XmlSerializerSection.cs
- DbBuffer.cs
- Debug.cs
- ConstraintCollection.cs
- RegexMatch.cs
- ReverseQueryOperator.cs
- DrawingGroup.cs
- ProxySimple.cs
- RegexRunner.cs
- EnumerableRowCollectionExtensions.cs
- FontFamilyConverter.cs
- CodePageUtils.cs
- GenericAuthenticationEventArgs.cs
- ColorIndependentAnimationStorage.cs
- SystemTcpStatistics.cs
- PropertyEntry.cs
- EntityDataSourceSelectingEventArgs.cs
- NonClientArea.cs
- ImageList.cs
- WorkflowApplication.cs
- odbcmetadatacollectionnames.cs
- RelationshipEndCollection.cs
- RegistryExceptionHelper.cs
- MetadataCache.cs
- GeneralTransform3DTo2DTo3D.cs
- WebPartConnectionsCancelVerb.cs
- SQLDoubleStorage.cs
- EncodingDataItem.cs
- Normalization.cs
- ChannelFactoryRefCache.cs
- FileNotFoundException.cs
- LogStream.cs
- WpfGeneratedKnownProperties.cs
- DataSpaceManager.cs
- WinFormsSpinner.cs
- TypeSource.cs
- DispatchWrapper.cs
- TabItemAutomationPeer.cs
- WorkflowRuntimeElement.cs
- StaticDataManager.cs
- HostingEnvironmentException.cs
- BamlLocalizationDictionary.cs
- PropertyInfoSet.cs
- CannotUnloadAppDomainException.cs
- SpellerError.cs
- CacheDependency.cs
- SecurityProtocolFactory.cs
- WmlTextViewAdapter.cs
- tooltip.cs
- TheQuery.cs
- SerializationObjectManager.cs
- RenamedEventArgs.cs
- MimeWriter.cs
- ResourcesBuildProvider.cs