File: UI\TraceContext.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="TraceContext.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
/*
 * The context for outputting trace information in the page.
 *
 * Copyright (c) 1999 Microsoft Corporation
 */
namespace System.Web {
    using System;
// 
    using System.Web.UI;
    using System.Web.Handlers;
    using System.Web.Util;
    using System.Web.SessionState;
    using System.Text;
    using System.Data;
    using System.Globalization;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.Security.Permissions;
    using System.Web.Configuration;
    using System.Threading;
    using System.ComponentModel;
 
    /// <devdoc>
    ///    <para>Captures and presents execution details about a Web request.</para>
    ///    <para>Use the TraceContext
    ///       class by appending trace messages to specific trace categories. For example, a
    ///       calendar class might append the message ?Calendar1-&gt;Starting
    ///       To Render? within the Render category, and append the message ?Calendar1-&gt;Firing OnChange Event? within
    ///       the Events category. Tracing is enabled by setting the <see topic='cpdirSystem.Web.UI.PageDirectives'/>
    ///       Trace attribute or the System.Web.UI.TraceContext.IsEnabled
    ///       property.</para>
    ///    <para>When tracing is enabled, In addition to showing
    ///       user-provided trace content, the <see cref='System.Web.UI.Page'/> class not only shows user-provided trace content, it automatically includes
    ///       performance data, tree-structure information, and state management content.</para>
    /// </devdoc>
 
    public sealed
        class TraceContext {
 
        private static DataSet  _masterRequest;
        private static bool     _writeToDiagnosticsTrace = false;
        private static readonly object EventTraceFinished = new object();
        private EventHandlerList _events = new EventHandlerList();
 
        private TraceMode       _traceMode;
        private TraceEnable     _isEnabled;
        private HttpContext     _context;
        private DataSet         _requestData;
        private long            _firstTime;
        private long            _lastTime;
        private int             _uniqueIdCounter = 0;
        private const string PAGEKEYNAME = "__PAGE";
        private const string NULLSTRING = "<null>"; // this will get HtmlEncoded later...
        private const string NULLIDPREFIX = "__UnassignedID";
        private ArrayList       _traceRecords;
 
        private bool            _endDataCollected;
        private bool            _writing = false;
 
        /// <devdoc>
        /// <para>Initializes a new instance of the <see cref='System.Web.TraceContext'/> class.</para>
        /// </devdoc>
        public TraceContext(HttpContext context) {
            _traceMode = TraceMode.Default;
            // Always disable trace in retail deployment mode (DevDiv 36396)
            _isEnabled = DeploymentSection.RetailInternal ? TraceEnable.Disable : TraceEnable.Default;
            _context = context;
            _firstTime = -1;
            _lastTime = -1;
            _endDataCollected = false;
            _traceRecords = new ArrayList();
        }
 
        /// <devdoc>
        ///    <para>Indicates the order in which trace messages should be
        ///       output to a requesting browser. Trace messages can be sorted in the order they
        ///       were processed, or alphabetically by user-defined category.</para>
        /// </devdoc>
        public TraceMode TraceMode {
            get {
                if (_traceMode == TraceMode.Default)
                    return HttpRuntime.Profile.OutputMode;
 
                return _traceMode;
            }
            set {
                if (value < TraceMode.SortByTime || value > TraceMode.Default) {
                    throw new ArgumentOutOfRangeException("value");
                }
                _traceMode = value;
 
                if (IsEnabled)
                    ApplyTraceMode();
            }
        }
 
        /// <devdoc>
        ///    <para>Indicates whether tracing is enabled for the current Web request.
        ///       Use this flag to check whether you should output tracing information before
        ///       writing anything to the trace log.</para>
        /// </devdoc>
        public bool IsEnabled {
            get {
                if (_isEnabled == TraceEnable.Default)
                    return HttpRuntime.Profile.IsEnabled;
                else {
                    return (_isEnabled == TraceEnable.Enable) ? true : false;
                }
            }
            set {
                // Always disable trace in retail deployment mode (DevDiv 36396)
                if (DeploymentSection.RetailInternal) {
                    System.Web.Util.Debug.Assert(_isEnabled == TraceEnable.Disable);
                    return;
                }
 
                if (value)
                    _isEnabled = TraceEnable.Enable;
                else
                    _isEnabled = TraceEnable.Disable;
            }
        }
 
 
        /// <devdoc>
        ///    <para>Indicates whether trace information should be output to a Web Forms
        ///       page. This property is used only in application-level tracing situations. You
        ///       can set this property in your application's config.web configuration file which
        ///       resides in the root directory of the application. </para>
        /// </devdoc>
        internal bool PageOutput {
            get {
                if (_isEnabled == TraceEnable.Default)
                    return HttpRuntime.Profile.PageOutput;
                else {
                    return (_isEnabled == TraceEnable.Enable) ? true : false;
                }
 
            }
        }
 
        // this is used only for error pages, called from Page.HandleError.
        internal int StatusCode {
            set {
                VerifyStart();
                DataRow row = _requestData.Tables[SR.Trace_Request].Rows[0];
                row[SR.Trace_Status_Code] = value;
            }
        }
 
 
        /// <devdoc>
        ///     Raised after the trace has been finished
        /// </devdoc>
        public event TraceContextEventHandler TraceFinished {
            add {
                _events.AddHandler(EventTraceFinished, value);
            }
            remove {
                _events.RemoveHandler(EventTraceFinished, value);
            }
        }
 
        private void ApplyTraceMode() {
            VerifyStart();
            if (TraceMode == TraceMode.SortByCategory)
                _requestData.Tables[SR.Trace_Trace_Information].DefaultView.Sort = SR.Trace_Category;
            else
                _requestData.Tables[SR.Trace_Trace_Information].DefaultView.Sort = SR.Trace_From_First;
        }
 
 
        internal void CopySettingsTo(TraceContext tc) {
            tc._traceMode = this._traceMode;
            tc._isEnabled = this._isEnabled;
        }
 
        internal void OnTraceFinished(TraceContextEventArgs e) {
            TraceContextEventHandler handler = (TraceContextEventHandler)_events[EventTraceFinished];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        internal static void SetWriteToDiagnosticsTrace(bool value) {
            _writeToDiagnosticsTrace = value;
        }
 
 
        /// <devdoc>
        ///    <para>Writes trace information to the trace log including any
        ///       user defined categories and trace messages.</para>
        /// </devdoc>
        public void Write(string message) {
            Write(String.Empty, message, null, false, _writeToDiagnosticsTrace);
        }
 
 
        /// <devdoc>
        ///    <para>Writes trace information to the trace log including any
        ///       user defined categories and trace messages.</para>
        /// </devdoc>
        public void Write(string category, string message) {
            Write(category, message, null, false, _writeToDiagnosticsTrace);
        }
 
 
        /// <devdoc>
        ///    <para>Writes trace information to the trace log including any user defined
        ///       categories,trace messages and error information.</para>
        /// </devdoc>
        public void Write(string category, string message, Exception errorInfo) {
            Write(category, message, errorInfo, false, _writeToDiagnosticsTrace);
        }
 
        internal void WriteInternal(string message, bool writeToDiagnostics) {
            Write(String.Empty, message, null, false, writeToDiagnostics);
        }
 
 
        internal void WriteInternal(string category, string message, bool writeToDiagnostics) {
            Write(category, message, null, false, writeToDiagnostics);
        }
 
 
        /// <devdoc>
        ///    <para>Writes trace information to the trace log including any
        ///       user defined categories and trace messages. All warnings appear as red text.</para>
        /// </devdoc>
        public void Warn(string message) {
            Write(String.Empty, message, null, true, _writeToDiagnosticsTrace);
        }
 
 
        /// <devdoc>
        ///    <para>Writes trace information to the trace log including any
        ///       user defined categories and trace messages. All warnings appear as red text.</para>
        /// </devdoc>
        public void Warn(string category, string message) {
            Write(category, message, null, true, _writeToDiagnosticsTrace);
        }
 
 
        /// <devdoc>
        ///    <para>Writes trace information to the trace log including any user defined categories,trace messages and error information. All
        ///       warnings appear as red text. </para>
        /// </devdoc>
        public void Warn(string category, string message, Exception errorInfo) {
            Write(category, message, errorInfo, true, _writeToDiagnosticsTrace);
        }
 
 
        internal void WarnInternal(string category, string message, bool writeToDiagnostics) {
            Write(category, message, null, true, writeToDiagnostics);
        }
 
        void Write(string category, string message, Exception errorInfo, bool isWarning, bool writeToDiagnostics) {
            // Guard against
            lock(this) {
                // Bail if trace isn't enabled or this is from our call to System.Diagonostics.Trace below
                if (!IsEnabled || _writing || _endDataCollected)
                    return;
 
                VerifyStart();
 
                if (category == null)
                    category = String.Empty;
 
                if (message == null)
                    message = String.Empty;
 
                long messagetime = Counter.Value;
 
                DataRow row = NewRow(_requestData, SR.Trace_Trace_Information);
                row[SR.Trace_Category] = category;
                row[SR.Trace_Message] = message;
                row[SR.Trace_Warning] = isWarning ? "yes" : "no";
                if (errorInfo != null) {
                    row["ErrorInfoMessage"] = errorInfo.Message;
                    row["ErrorInfoStack"] = errorInfo.StackTrace;
                }
 
                if (_firstTime != -1) {
                    row[SR.Trace_From_First] = (((double)(messagetime - _firstTime)) / Counter.Frequency);
                }
                else
                    _firstTime = messagetime;
 
                if (_lastTime != -1) {
                    row[SR.Trace_From_Last] = (((double)(messagetime - _lastTime)) / Counter.Frequency);
                }
                _lastTime = messagetime;
                AddRow(_requestData, SR.Trace_Trace_Information, row);
 
                string msg = message;
                if (errorInfo != null) {
                    string eMsg = errorInfo.Message;
                    if (eMsg == null) eMsg = String.Empty;
                    string eTrace = errorInfo.StackTrace;
                    if (eTrace == null) eTrace = String.Empty;
                    StringBuilder str = new StringBuilder(message.Length + eMsg.Length + eTrace.Length);
                    str.Append(message);
                    str.Append(" -- ");
                    str.Append(eMsg);
                    str.Append(": ");
                    str.Append(eTrace);
                    msg = str.ToString();
                }
 
                if (writeToDiagnostics) {
                    _writing = true;
                    System.Diagnostics.Trace.WriteLine(msg, category);
                    _writing = false;
                }
 
                // Send to IIS tracing
                if (_context != null && _context.WorkerRequest != null) {
                    _context.WorkerRequest.RaiseTraceEvent(isWarning ? IntegratedTraceType.TraceWarn : IntegratedTraceType.TraceWrite, msg);
                }
                
            }
 
            // Add the trace record to our collection
            _traceRecords.Add(new TraceContextRecord(category, message, isWarning, errorInfo));
        }
 
        internal void AddNewControl(string id, string parentId, string type, int viewStateSize, int controlStateSize) {
            VerifyStart();
 
            DataRow row = NewRow(_requestData, SR.Trace_Control_Tree);
 
            if (id == null)
                id = NULLIDPREFIX+(_uniqueIdCounter++);
            row[SR.Trace_Control_Id] = id;
 
            if (parentId == null)
                parentId = PAGEKEYNAME;
            row[SR.Trace_Parent_Id] = parentId;
 
            row[SR.Trace_Type] = type;
            row[SR.Trace_Viewstate_Size] = viewStateSize;
            row[SR.Trace_Controlstate_Size] = controlStateSize;
            row[SR.Trace_Render_Size] = 0;
            try {
                AddRow(_requestData, SR.Trace_Control_Tree, row);
            }
            catch (ConstraintException) {
                throw new HttpException(SR.GetString(SR.Duplicate_id_used, id, "Trace"));
            }
 
        }
 
        /*
         *   Add the render size to the control
         */
        internal void AddControlSize(String controlId, int renderSize) {
            VerifyStart();
 
            DataTable dt = _requestData.Tables[SR.Trace_Control_Tree];
 
            // find the row for this control
            if (controlId == null)
                controlId = PAGEKEYNAME;
            DataRow row = dt.Rows.Find((object) controlId);
            // if the row is null, we couldn't find it, so we'll just skip this control
            if (row != null)
                row[SR.Trace_Render_Size] = renderSize;
        }
 
        internal void AddControlStateSize(String controlId, int viewstateSize, int controlstateSize) {
            VerifyStart();
 
            DataTable dt = _requestData.Tables[SR.Trace_Control_Tree];
 
            // find the row for this control
            if (controlId == null)
                controlId = PAGEKEYNAME;
            DataRow row = dt.Rows.Find((object) controlId);
            // if the row is null, we couldn't find it, so we'll just skip this control
            if (row != null) {
                row[SR.Trace_Viewstate_Size] = viewstateSize;
                row[SR.Trace_Controlstate_Size] = controlstateSize;
            }
        }
 
 
        internal void Render(HtmlTextWriter output) {
            if (PageOutput && _requestData != null) {
 
                TraceEnable oldEnabled = _isEnabled;
 
                _isEnabled = TraceEnable.Disable;
 
                Control table;
 
                output.Write("<div id=\"__asptrace\">\r\n");
                output.Write(TraceHandler.StyleSheet);
                output.Write("<span class=\"tracecontent\">\r\n");
 
                table = TraceHandler.CreateDetailsTable(_requestData.Tables[SR.Trace_Request]);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateTraceTable(_requestData.Tables[SR.Trace_Trace_Information]);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateControlTable(_requestData.Tables[SR.Trace_Control_Tree]);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Session_State], true /*encodeSpaces*/);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Application_State], true /*encodeSpaces*/);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Request_Cookies_Collection], true /*encodeSpaces*/);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Response_Cookies_Collection], true /*encodeSpaces*/);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Headers_Collection], true /*encodeSpaces*/);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Response_Headers_Collection], true /*encodeSpaces*/);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Form_Collection]);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Querystring_Collection]);
                if (table != null)
                    table.RenderControl(output);
 
                table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Server_Variables], true /*encodeSpaces*/);
                if (table != null)
                    table.RenderControl(output);
 
                output.Write("<hr width=100% size=1 color=silver>\r\n\r\n");
                output.Write(SR.GetString(SR.Error_Formatter_CLR_Build) + VersionInfo.ClrVersion +
                             SR.GetString(SR.Error_Formatter_ASPNET_Build) + VersionInfo.EngineVersion + "\r\n\r\n");
                output.Write("</font>\r\n\r\n");
 
                output.Write("</span>\r\n</div>\r\n");
 
                _isEnabled = oldEnabled;
            }
        }
 
        internal DataSet GetData() {
            return _requestData;
        }
 
        internal void VerifyStart() {
            // if we have already started, we can skip the lock
            if (_masterRequest == null) {
                // otherwise we need to make sure two
                // requests don't try to call InitMaster at the same time
                lock(this) {
                    if (_masterRequest == null)
                        InitMaster();
                }
            }
 
            if (_requestData == null) {
                InitRequest();
            }
        }
 
        internal void StopTracing() {
            _endDataCollected = true;
        }
 
        /*
         *   Finalize the request
         */
        internal void EndRequest() {
            VerifyStart();
 
            if (_endDataCollected)
                return;
 
            // add some more information about the reponse
            DataRow row = _requestData.Tables[SR.Trace_Request].Rows[0];
            row[SR.Trace_Status_Code] = _context.Response.StatusCode;
            row[SR.Trace_Response_Encoding] = _context.Response.ContentEncoding.EncodingName;
 
            IEnumerator en;
            string temp;
            object obj;
            int i;
 
 
            // Application State info
            _context.Application.Lock();
            try {
                en = _context.Application.GetEnumerator();
                while (en.MoveNext()) {
                    row = NewRow(_requestData, SR.Trace_Application_State);
                    temp = (string) en.Current;
 
                    //the key might be null
                    row[SR.Trace_Application_Key] = (temp != null) ? temp : NULLSTRING;
 
                    obj = _context.Application[temp];
 
                    // the value could also be null
                    if (obj != null) {
                        row[SR.Trace_Type] = obj.GetType();
                        row[SR.Trace_Value] = obj.ToString();
                    }
                    else {
                        row[SR.Trace_Type] = NULLSTRING;
                        row[SR.Trace_Value] = NULLSTRING;
                    }
 
                    AddRow(_requestData, SR.Trace_Application_State, row);
                }
            }
            finally {
                _context.Application.UnLock();
            }
 
            // request cookie info
            HttpCookieCollection cookieCollection = new HttpCookieCollection();
            _context.Request.FillInCookiesCollection(cookieCollection, false /*includeResponse */);
            HttpCookie[] cookies = new HttpCookie[cookieCollection.Count];
            cookieCollection.CopyTo(cookies, 0);
            for (i = 0; i<cookies.Length; i++) {
                row = NewRow(_requestData, SR.Trace_Request_Cookies_Collection);
                row[SR.Trace_Name] = cookies[i].Name;
                if (cookies[i].Values.HasKeys()) {
                    NameValueCollection subvalues = cookies[i].Values;
                    StringBuilder sb = new StringBuilder();
 
                    en = subvalues.GetEnumerator();
                    while (en.MoveNext()) {
                        temp = (string) en.Current;
                        sb.Append("(");
                        sb.Append(temp + "=");
 
                        sb.Append(cookies[i][temp] + ")  ");
                    }
                    row[SR.Trace_Value] = sb.ToString();
                }
                else
                    row[SR.Trace_Value] = cookies[i].Value;
 
                int size =  (cookies[i].Name  == null) ? 0 : cookies[i].Name.Length;
                size += (cookies[i].Value == null) ? 0 : cookies[i].Value.Length;
 
                row[SR.Trace_Size] = size + 1; // plus 1 for =
                AddRow(_requestData, SR.Trace_Request_Cookies_Collection, row);
            }
 
            // response cookie info
            cookies = new HttpCookie[_context.Response.Cookies.Count];
            _context.Response.Cookies.CopyTo(cookies, 0);
            for (i = 0; i<cookies.Length; i++) {
                row = NewRow(_requestData, SR.Trace_Response_Cookies_Collection);
                row[SR.Trace_Name] = cookies[i].Name;
                if (cookies[i].Values.HasKeys()) {
                    NameValueCollection subvalues = cookies[i].Values;
                    StringBuilder sb = new StringBuilder();
 
                    en = subvalues.GetEnumerator();
                    while (en.MoveNext()) {
                        temp = (string) en.Current;
                        sb.Append("(");
                        sb.Append(temp + "=");
 
                        sb.Append(cookies[i][temp] + ")  ");
                    }
                    row[SR.Trace_Value] = sb.ToString();
                }
                else
                    row[SR.Trace_Value] = cookies[i].Value;
 
                int size =  (cookies[i].Name  == null) ? 0 : cookies[i].Name.Length;
                size += (cookies[i].Value == null) ? 0 : cookies[i].Value.Length;
 
                row[SR.Trace_Size] = size + 1; // plus 1 for =
                AddRow(_requestData, SR.Trace_Response_Cookies_Collection, row);
            }
 
            HttpSessionState session = _context.Session;
            // session state info
            if (session != null) {
                row = _requestData.Tables[SR.Trace_Request].Rows[0];
                try {
                    row[SR.Trace_Session_Id] = HttpUtility.UrlEncode(session.SessionID);
                }
                catch {
                    // VSWhidbey 527536
                    // Accessing SessionID can cause creation of the session id, this will throw in the
                    // cross page post scenario, as the response has already been flushed when we try
                    // to add the session cookie, since this is just trace output, we can just not set a session ID.
                    // 
                }
 
                en = session.GetEnumerator();
                while (en.MoveNext()) {
                    row = NewRow(_requestData, SR.Trace_Session_State);
 
                    temp = (string) en.Current;
 
                    // the key could be null
                    row[SR.Trace_Session_Key] = (temp != null) ? temp : NULLSTRING;
 
                    obj = session[temp];
 
                    // the value could also be null
                    if (obj != null) {
                        row[SR.Trace_Type] = obj.GetType();
                        row[SR.Trace_Value] = obj.ToString();
                    }
                    else {
                        row[SR.Trace_Type] = NULLSTRING;
                        row[SR.Trace_Value] = NULLSTRING;
                    }
 
                    AddRow(_requestData, SR.Trace_Session_State, row);
                }
            }
 
            ApplyTraceMode();
            OnTraceFinished(new TraceContextEventArgs(_traceRecords));
        }
 
        /*  InitMaster
         *  Initialize the _masterRequest dataset with the schema we use
         *  to store profiling information
         */
        private void InitMaster() {
            DataSet tempset = new DataSet();
            tempset.Locale = CultureInfo.InvariantCulture;
 
            // populate the _masterRequest's schema
            DataTable tab;
            Type strtype = typeof(string);
            Type inttype = typeof(int);
            Type doubletype = typeof(double);
 
            // request table
            tab = tempset.Tables.Add(SR.Trace_Request);
            tab.Columns.Add(SR.Trace_No, inttype);
            tab.Columns.Add(SR.Trace_Time_of_Request, strtype);
            tab.Columns.Add(SR.Trace_Url, strtype);
            tab.Columns.Add(SR.Trace_Request_Type, strtype);
            tab.Columns.Add(SR.Trace_Status_Code, inttype);
            tab.Columns.Add(SR.Trace_Session_Id, strtype);
            tab.Columns.Add(SR.Trace_Request_Encoding, strtype);
            tab.Columns.Add(SR.Trace_Response_Encoding, strtype);
 
            // control heirarchy table
            tab = tempset.Tables.Add(SR.Trace_Control_Tree);
            tab.Columns.Add(SR.Trace_Parent_Id, strtype);
 
            DataColumn[] col = new DataColumn[1];
            col[0] = new DataColumn(SR.Trace_Control_Id, strtype);
            tab.Columns.Add(col[0]);
            tab.PrimaryKey = col;   // set the control id to be the primary key
 
            tab.Columns.Add(SR.Trace_Type, strtype);
            tab.Columns.Add(SR.Trace_Render_Size, inttype);
            tab.Columns.Add(SR.Trace_Viewstate_Size, inttype);
            tab.Columns.Add(SR.Trace_Controlstate_Size, inttype);
 
            // session state table
            tab = tempset.Tables.Add(SR.Trace_Session_State);
            tab.Columns.Add(SR.Trace_Session_Key, strtype);
            tab.Columns.Add(SR.Trace_Type, strtype);
            tab.Columns.Add(SR.Trace_Value, strtype);
 
            // application state table
            tab = tempset.Tables.Add(SR.Trace_Application_State);
            tab.Columns.Add(SR.Trace_Application_Key, strtype);
            tab.Columns.Add(SR.Trace_Type, strtype);
            tab.Columns.Add(SR.Trace_Value, strtype);
 
            // request cookies table
            tab = tempset.Tables.Add(SR.Trace_Request_Cookies_Collection);
            tab.Columns.Add(SR.Trace_Name, strtype);
            tab.Columns.Add(SR.Trace_Value, strtype);
            tab.Columns.Add(SR.Trace_Size, inttype);
 
            // resposne cookies table
            tab = tempset.Tables.Add(SR.Trace_Response_Cookies_Collection);
            tab.Columns.Add(SR.Trace_Name, strtype);
            tab.Columns.Add(SR.Trace_Value, strtype);
            tab.Columns.Add(SR.Trace_Size, inttype);
 
            // header table
            tab = tempset.Tables.Add(SR.Trace_Headers_Collection);
            tab.Columns.Add(SR.Trace_Name, strtype);
            tab.Columns.Add(SR.Trace_Value, strtype);
 
            // response header table
            tab = tempset.Tables.Add(SR.Trace_Response_Headers_Collection);
            tab.Columns.Add(SR.Trace_Name, strtype);
            tab.Columns.Add(SR.Trace_Value, strtype);
 
            // form variables table
            tab = tempset.Tables.Add(SR.Trace_Form_Collection);
            tab.Columns.Add(SR.Trace_Name, strtype);
            tab.Columns.Add(SR.Trace_Value, strtype);
 
            // querystring table
            tab = tempset.Tables.Add(SR.Trace_Querystring_Collection);
            tab.Columns.Add(SR.Trace_Name, strtype);
            tab.Columns.Add(SR.Trace_Value, strtype);
 
            // trace info
            tab = tempset.Tables.Add(SR.Trace_Trace_Information);
            tab.Columns.Add(SR.Trace_Category, strtype);
            tab.Columns.Add(SR.Trace_Warning, strtype);
            tab.Columns.Add(SR.Trace_Message, strtype);
            tab.Columns.Add(SR.Trace_From_First, doubletype);
            tab.Columns.Add(SR.Trace_From_Last, doubletype);
            tab.Columns.Add("ErrorInfoMessage", strtype);
            tab.Columns.Add("ErrorInfoStack", strtype);
 
            // server variables
            tab = tempset.Tables.Add(SR.Trace_Server_Variables);
            tab.Columns.Add(SR.Trace_Name, strtype);
            tab.Columns.Add(SR.Trace_Value, strtype);
 
            _masterRequest = tempset;
        }
 
        private DataRow NewRow(DataSet ds, string table) {
            return ds.Tables[table].NewRow();
        }
 
        private void AddRow(DataSet ds, string table, DataRow row) {
            ds.Tables[table].Rows.Add(row);
        }
 
        /*  InitRequest
         *  Initialize the given dataset with basic
         *  request information
         */
        private void InitRequest() {
            // Master request is assumed to be initialized first
            System.Web.Util.Debug.Assert(_masterRequest != null);
 
            DataSet requestData = _masterRequest.Clone();
 
            // request info
            DataRow row = NewRow(requestData, SR.Trace_Request);
            row[SR.Trace_Time_of_Request] = _context.Timestamp.ToString("G");
 
            string url = _context.Request.RawUrl;
            int loc = url.IndexOf("?", StringComparison.Ordinal);
            if (loc != -1)
                url = url.Substring(0, loc);
            row[SR.Trace_Url] = url;
 
            row[SR.Trace_Request_Type] = _context.Request.HttpMethod;
            try {
                row[SR.Trace_Request_Encoding] = _context.Request.ContentEncoding.EncodingName;
            }
            catch {
                // if we get an exception getting the ContentEncoding, most likely
                // there's an error in the config file.  Just ignore it so we can finish InitRequest.
            }
 
            if (TraceMode == TraceMode.SortByCategory)
                requestData.Tables[SR.Trace_Trace_Information].DefaultView.Sort = SR.Trace_Category;
            AddRow(requestData, SR.Trace_Request, row);
 
            // header info
            try {
                // Bug 867196: Use Request.Unvalidated to ensure request validation will not
                // be triggered when the entries of the collection are accessed.
                AddCollectionToRequestData(requestData, SR.Trace_Headers_Collection, _context.Request.Unvalidated.Headers);
            }
            catch {
                // ---- exceptions when we fail to get the unvalidated collection
            }
 
            // response header info
            ArrayList headers = _context.Response.GenerateResponseHeaders(false);
            int n = (headers != null) ? headers.Count : 0;
            for (int i = 0; i < n; i++) {
                HttpResponseHeader h = (HttpResponseHeader)headers[i];
                row = NewRow(requestData, SR.Trace_Response_Headers_Collection);
                row[SR.Trace_Name] = h.Name;
                row[SR.Trace_Value] = h.Value;
                AddRow(requestData, SR.Trace_Response_Headers_Collection, row);
            }
 
            //form info
            try {
                AddCollectionToRequestData(requestData, SR.Trace_Form_Collection, _context.Request.Unvalidated.Form);
            }
            catch {
                // ---- exceptions when we fail to get the unvalidated collection
            }
 
            //QueryString info
            try {
                AddCollectionToRequestData(requestData, SR.Trace_Querystring_Collection, _context.Request.Unvalidated.QueryString);
            }
            catch {
                // ---- exceptions when we fail to get the unvalidated collection
            }
 
            //Server Variable info
            if (HttpRuntime.HasAppPathDiscoveryPermission()) {
                AddCollectionToRequestData(requestData, SR.Trace_Server_Variables, _context.Request.ServerVariables);
            }
 
            _requestData = requestData;
 
            if (HttpRuntime.UseIntegratedPipeline) {
                // Dev10 914119: When trace is enabled, the request entity is read and no longer
                // available to IIS.  In integrated mode, we have an API that allows us to reinsert
                // the entity.  Although it is expensive, performance is not a concern when
                // trace is enalbed, so we will reinsert just in case a native handler needs
                // to access the entity.  I decided not to check the current handler, since
                // that can be changed if someone sets the IIS script map.
                _context.Request.InsertEntityBody();
            }
        }
 
        private void AddCollectionToRequestData(DataSet requestData, string traceCollectionTitle, NameValueCollection collection) {
            if (null != collection) {
                var keys = collection.AllKeys;
                for (int i = 0; i < keys.Length; i++) {
                    var row = NewRow(requestData, traceCollectionTitle);
                    row[SR.Trace_Name] = keys[i];
                    row[SR.Trace_Value] = collection[keys[i]];
                    AddRow(requestData, traceCollectionTitle, row);
                }
            }
        }
    }
}