1 //------------------------------------------------------------------------------
2 // <copyright file="TraceHandler.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
10 * Copyright (c) 1998-1999, Microsoft Corporation
13 namespace System.Web.Handlers {
15 using System.Collections;
17 using System.Globalization;
18 using System.Web.Configuration;
19 using System.Web.Hosting;
21 using System.Web.UI.WebControls;
22 using System.Web.UI.HtmlControls;
23 using System.Web.Util;
24 using System.Web.SessionState;
28 using System.Security.Permissions;
31 /// <para>[To be supplied.]</para>
33 public class TraceHandler : IHttpHandler {
34 private const string _style =
35 "<style type=\"text/css\">\r\n" +
36 "span.tracecontent b { color:white }\r\n" +
37 "span.tracecontent { background-color:white; color:black;font: 10pt verdana, arial; }\r\n" +
38 "span.tracecontent table { clear:left; font: 10pt verdana, arial; cellspacing:0; cellpadding:0; margin-bottom:25}\r\n" +
39 "span.tracecontent tr.subhead { background-color:#cccccc;}\r\n" +
40 "span.tracecontent th { padding:0,3,0,3 }\r\n" +
41 "span.tracecontent th.alt { background-color:black; color:white; padding:3,3,2,3; }\r\n" +
42 "span.tracecontent td { color: black; padding:0,3,0,3; text-align: left }\r\n" +
43 "span.tracecontent td.err { color: red; }\r\n" +
44 "span.tracecontent tr.alt { background-color:#eeeeee }\r\n" +
45 "span.tracecontent h1 { font: 24pt verdana, arial; margin:0,0,0,0}\r\n" +
46 "span.tracecontent h2 { font: 18pt verdana, arial; margin:0,0,0,0}\r\n" +
47 "span.tracecontent h3 { font: 12pt verdana, arial; margin:0,0,0,0}\r\n" +
48 "span.tracecontent th a { color:darkblue; font: 8pt verdana, arial; }\r\n" +
49 "span.tracecontent a { color:darkblue;text-decoration:none }\r\n" +
50 "span.tracecontent a:hover { color:darkblue;text-decoration:underline; }\r\n" +
51 "span.tracecontent div.outer { width:90%; margin:15,15,15,15}\r\n" +
52 "span.tracecontent table.viewmenu td { background-color:#006699; color:white; padding:0,5,0,5; }\r\n" +
53 "span.tracecontent table.viewmenu td.end { padding:0,0,0,0; }\r\n" +
54 "span.tracecontent table.viewmenu a {color:white; font: 8pt verdana, arial; }\r\n" +
55 "span.tracecontent table.viewmenu a:hover {color:white; font: 8pt verdana, arial; }\r\n" +
56 "span.tracecontent a.tinylink {color:darkblue; background-color:black; font: 8pt verdana, arial;text-decoration:underline;}\r\n" +
57 "span.tracecontent a.link {color:darkblue; text-decoration:underline;}\r\n" +
58 "span.tracecontent div.buffer {padding-top:7; padding-bottom:17;}\r\n" +
59 "span.tracecontent .small { font: 8pt verdana, arial }\r\n" +
60 "span.tracecontent table td { padding-right:20 }\r\n" +
61 "span.tracecontent table td.nopad { padding-right:5 }\r\n" +
64 private HttpContext _context;
65 private HttpResponse _response;
66 private HttpRequest _request;
67 private HtmlTextWriter _writer;
69 [SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
70 public TraceHandler() {
73 // IHttpMethods exposed to derived classes
75 protected void ProcessRequest(HttpContext context) {
76 ((IHttpHandler)this).ProcessRequest(context);
79 protected bool IsReusable {
81 return ((IHttpHandler)this).IsReusable;
85 void IHttpHandler.ProcessRequest(HttpContext context) {
86 // VSWhidbey 448844: Disable handler if retail is set to true
87 if (DeploymentSection.RetailInternal ||
88 (!context.Request.IsLocal && HttpRuntime.Profile.LocalOnly)) {
89 HttpException e = new HttpException(403, null);
90 e.SetFormatter(new TraceHandlerErrorFormatter(!DeploymentSection.RetailInternal));
95 _response = _context.Response;
96 _request = _context.Request;
97 _writer = Page.CreateHtmlTextWriterInternal(_response.Output, _request);
99 // if we're in integrated mode, we need to set the content type explicitly
100 if (context.WorkerRequest is IIS7WorkerRequest) {
101 _response.ContentType = _request.Browser.PreferredRenderingMime;
104 if (_writer == null) {
105 // Can't create a writer, horked at this point, just return
109 _context.Trace.IsEnabled = false;
111 // Validate the input to prevent XSS attacks.
112 _request.ValidateInput();
114 _writer.Write("<html>\r\n");
115 _writer.Write("<head>\r\n");
116 _writer.Write(StyleSheet);
117 _writer.Write("</head>\r\n");
119 _writer.Write("<body>\r\n");
120 _writer.Write("<span class=\"tracecontent\">\r\n");
122 if (!HttpRuntime.Profile.IsConfigEnabled) {
123 HttpException e = new HttpException();
124 e.SetFormatter(new TraceHandlerErrorFormatter(false));
128 IList datasets = HttpRuntime.Profile.GetData();
130 // first check if we should clear data
131 if (_request.QueryString["clear"] != null) {
132 HttpRuntime.Profile.Reset();
133 string url = _request.RawUrl;
134 _response.Redirect(url.Substring(0, url.IndexOf("?", StringComparison.Ordinal)));
137 // then check if we are drilling down
138 string strid = _request.QueryString["id"];
140 int index = Int32.Parse(strid, CultureInfo.InvariantCulture);
141 if (index >=0 && index < datasets.Count) {
142 ShowDetails((DataSet) datasets[index]);
143 ShowVersionDetails();
144 _writer.Write("</span>\r\n</body>\r\n</html>\r\n");
149 // if we get here, its just generic request
150 ShowRequests(datasets);
151 ShowVersionDetails();
152 _writer.Write("</span>\r\n</body>\r\n</html>\r\n");
155 bool IHttpHandler.IsReusable {
156 get { return false; }
159 protected void ShowDetails(DataSet data) {
160 if (data == null) return;
164 _writer.Write("<h1>" + SR.GetString(SR.Trace_Request_Details) + "</h1><br>");
166 table = CreateDetailsTable(data.Tables[SR.Trace_Request]);
168 table.RenderControl(_writer);
170 table = CreateTraceTable(data.Tables[SR.Trace_Trace_Information]);
172 table.RenderControl(_writer);
174 table = CreateControlTable(data.Tables[SR.Trace_Control_Tree]);
176 table.RenderControl(_writer);
178 table = CreateTable(data.Tables[SR.Trace_Session_State], true /*encodeSpaces*/);
180 table.RenderControl(_writer);
182 table = CreateTable(data.Tables[SR.Trace_Application_State], true /*encodeSpaces*/);
184 table.RenderControl(_writer);
186 table = CreateTable(data.Tables[SR.Trace_Request_Cookies_Collection], true /*encodeSpaces*/);
188 table.RenderControl(_writer);
190 table = CreateTable(data.Tables[SR.Trace_Response_Cookies_Collection], true /*encodeSpaces*/);
192 table.RenderControl(_writer);
194 table = CreateTable(data.Tables[SR.Trace_Headers_Collection], true /*encodeSpaces*/);
196 table.RenderControl(_writer);
198 table = CreateTable(data.Tables[SR.Trace_Form_Collection]);
200 table.RenderControl(_writer);
202 table = CreateTable(data.Tables[SR.Trace_Querystring_Collection]);
204 table.RenderControl(_writer);
206 table = CreateTable(data.Tables[SR.Trace_Server_Variables], true /*encodeSpaces*/);
208 table.RenderControl(_writer);
212 protected void ShowVersionDetails() {
213 _writer.Write("<hr width=100% size=1 color=silver>\r\n\r\n");
214 _writer.Write(SR.GetString(SR.Error_Formatter_CLR_Build) + VersionInfo.ClrVersion +
215 SR.GetString(SR.Error_Formatter_ASPNET_Build) + VersionInfo.EngineVersion + "\r\n\r\n");
216 _writer.Write("</font>\r\n\r\n");
219 protected void ShowRequests(IList data) {
220 // add the title, application name, physical path, etc.
221 Table table = new Table();
222 table.CellPadding = 0;
223 table.CellSpacing = 0;
224 table.Width = Unit.Percentage(100);
225 TableRow trow = AddRow(table);
228 AddCell(trow, SR.GetString(SR.Trace_Application_Trace));
230 string vroot = _request.ApplicationPath;
231 int vrootLen = vroot.Length;
233 trow = AddRow(table);
234 AddCell(trow, "<h2>" + HttpUtility.HtmlEncode(vroot.Substring(1)) + "<h2><p>");
236 trow = AddRow(table);
237 AddCell(trow, "[ <a href=\"Trace.axd?clear=1\" class=\"link\">" + SR.GetString(SR.Trace_Clear_Current) + "</a> ]");
239 // check if we have permission to show the physical path. If not, don't show anything.
240 string physicalPath = " ";
241 if (HttpRuntime.HasAppPathDiscoveryPermission())
242 physicalPath = SR.GetString(SR.Trace_Physical_Directory) + _request.PhysicalApplicationPath;
243 trow = AddRow(table);
244 tcell = AddCell(trow, physicalPath);
246 table.RenderControl(_writer);
248 //////// add the table of requests ///////
250 table.CellPadding = 0;
251 table.CellSpacing = 0;
252 table.Width = Unit.Percentage(100);
254 trow = AddRow(table);
256 // title for the table
257 tcell = AddHeaderCell(trow, "<h3><b>" + SR.GetString(SR.Trace_Requests_This) + "</b></h3>");
258 tcell.ColumnSpan = 5;
259 tcell.CssClass = "alt";
260 tcell.HorizontalAlign = HorizontalAlign.Left;
262 tcell = AddHeaderCell(trow, SR.GetString(SR.Trace_Remaining) + " " + HttpRuntime.Profile.RequestsRemaining.ToString(NumberFormatInfo.InvariantInfo));
263 tcell.CssClass = "alt";
264 tcell.HorizontalAlign = HorizontalAlign.Right;
267 // add headers for the columns
268 trow = AddRow(table);
269 trow.HorizontalAlign = HorizontalAlign.Left;
270 trow.CssClass = "subhead";
271 AddHeaderCell(trow, SR.GetString(SR.Trace_No));
272 AddHeaderCell(trow, SR.GetString(SR.Trace_Time_of_Request));
273 AddHeaderCell(trow, SR.GetString(SR.Trace_File));
274 AddHeaderCell(trow, SR.GetString(SR.Trace_Status_Code));
275 AddHeaderCell(trow, SR.GetString(SR.Trace_Verb));
276 AddHeaderCell(trow, " ");
278 // now fill the table with requests
280 for (int i = 0; i < data.Count; i++) {
282 DataSet current = (DataSet)data[i];
283 trow = AddRow(table);
285 trow.CssClass = "alt";
287 AddCell(trow, (i + 1).ToString(NumberFormatInfo.InvariantInfo));
288 AddCell(trow, (string) current.Tables[SR.Trace_Request].Rows[0][SR.Trace_Time_of_Request]);
289 AddCell(trow, HttpUtility.HtmlEncode((string) current.Tables[SR.Trace_Request].Rows[0][SR.Trace_Url]).Substring(vrootLen));
290 AddCell(trow, current.Tables[SR.Trace_Request].Rows[0][SR.Trace_Status_Code].ToString());
291 AddCell(trow, (string) current.Tables[SR.Trace_Request].Rows[0][SR.Trace_Request_Type]);
293 TableCell linkcell = AddCell(trow, String.Empty);
294 HtmlAnchor a = new HtmlAnchor();
295 a.HRef = "Trace.axd?id=" + i;
296 a.InnerHtml = "<nobr>" + SR.GetString(SR.Trace_View_Details);
297 a.Attributes["class"] = "link";
298 linkcell.Controls.Add(a);
302 table.RenderControl(_writer);
305 ////// Static methods for creating tables //////////
306 static private TableRow AddRow(Table t) {
307 TableRow trow = new TableRow();
312 static private TableCell AddHeaderCell(TableRow trow, string text) {
313 TableHeaderCell tcell = new TableHeaderCell();
315 trow.Cells.Add(tcell);
319 static private TableCell AddCell(TableRow trow, string text) {
320 TableCell tcell = new TableCell();
322 trow.Cells.Add(tcell);
326 static internal string StyleSheet {
327 get { return _style;}
330 static internal Table CreateControlTable(DataTable datatable) {
331 Table table = new Table();
332 if (datatable == null) return table;
339 Hashtable indentLevels = new Hashtable();
343 table.Width = Unit.Percentage(100);
344 table.CellPadding = 0;
345 table.CellSpacing = 0;
348 // add a title for the table - same as table name
349 trow = AddRow(table);
350 tcell = AddHeaderCell(trow, "<h3><b>" + SR.GetString(datatable.TableName) + "</b></h3>");
351 tcell.CssClass = "alt";
352 tcell.ColumnSpan = 5;
353 tcell.HorizontalAlign = HorizontalAlign.Left;
355 // add the header information
356 trow = AddRow(table);
357 trow.CssClass = "subhead";
358 trow.HorizontalAlign = HorizontalAlign.Left;
359 AddHeaderCell(trow, SR.GetString(SR.Trace_Control_Id));
360 AddHeaderCell(trow, SR.GetString(SR.Trace_Type));
361 AddHeaderCell(trow, SR.GetString(SR.Trace_Render_Size_children));
362 AddHeaderCell(trow, SR.GetString(SR.Trace_Viewstate_Size_Nochildren));
363 AddHeaderCell(trow, SR.GetString(SR.Trace_Controlstate_Size_Nochildren));
365 // prime the indentLevels hashtable with an initial value
366 indentLevels["ROOT"] = 0;
369 en = datatable.Rows.GetEnumerator();
370 while (en.MoveNext()) {
371 // DevDivBugs 173345: Error when enabling trace in an ASPX page
372 // We also need to HtmlEncode parentId, as we HtmlEncode the controlId.
373 parent = HttpUtility.HtmlEncode ((string) ((DataRow) en.Current)[SR.Trace_Parent_Id]);
374 control = HttpUtility.HtmlEncode((string) ((DataRow) en.Current)[SR.Trace_Control_Id]);
376 // this lets us determine how far to indent each control
377 indent = (int) indentLevels[parent];
378 indentLevels[control] = indent + 1;
381 StringBuilder indentedControl = new StringBuilder();
383 // Don't want the ID's to break across lines
384 indentedControl.Append("<nobr>");
385 for (int i=0; i<indent; i++)
386 indentedControl.Append(" ");
388 // page has a blank ID, so we'll fill in something nice for it
389 if (control.Length == 0)
390 indentedControl.Append(SR.GetString(SR.Trace_Page));
392 indentedControl.Append(control);
394 trow = AddRow(table);
395 AddCell(trow, indentedControl.ToString());
396 AddCell(trow, (string) ((DataRow) en.Current)[SR.Trace_Type]);
398 object size = ((DataRow) en.Current)[SR.Trace_Render_Size];
400 AddCell(trow, ((int) size).ToString(NumberFormatInfo.InvariantInfo));
402 AddCell(trow, "---");
404 size = ((DataRow) en.Current)[SR.Trace_Viewstate_Size];
406 AddCell(trow, ((int) size).ToString(NumberFormatInfo.InvariantInfo));
408 AddCell(trow, "---");
410 size = ((DataRow) en.Current)[SR.Trace_Controlstate_Size];
412 AddCell(trow, ((int) size).ToString(NumberFormatInfo.InvariantInfo));
414 AddCell(trow, "---");
418 trow.CssClass = "alt";
425 static internal Table CreateTraceTable(DataTable datatable) {
426 Table table = new Table();
427 table.Width = Unit.Percentage(100);
428 table.CellPadding = 0;
429 table.CellSpacing = 0;
431 if (datatable == null) return table;
439 // add a title for the table - same as table name
440 trow = AddRow(table);
441 tcell = AddHeaderCell(trow, "<h3><b>" + SR.GetString(datatable.TableName) + "</b></h3>");
442 tcell.CssClass = "alt";
443 tcell.ColumnSpan = 10;
444 tcell.HorizontalAlign = HorizontalAlign.Left;
446 // add the header information - same as column names
447 trow = AddRow(table);
448 trow.CssClass = "subhead";
449 trow.HorizontalAlign = HorizontalAlign.Left;
450 AddHeaderCell(trow, SR.GetString(SR.Trace_Category));
451 AddHeaderCell(trow, SR.GetString(SR.Trace_Message));
452 AddHeaderCell(trow, SR.GetString(SR.Trace_From_First));
453 AddHeaderCell(trow, SR.GetString(SR.Trace_From_Last));
455 // now fill in the values, but don't display null values
456 en = datatable.DefaultView.GetEnumerator();
457 while (en.MoveNext()) {
458 trow = AddRow(table);
459 datarow = ((DataRowView) en.Current).Row;
461 bool isErr = datarow[SR.Trace_Warning].Equals("yes");
463 // FormatPlainTextAsHtml the values first
464 tcell = AddCell(trow, HttpUtility.FormatPlainTextAsHtml((string) datarow[SR.Trace_Category]));
465 if (isErr) tcell.CssClass = "err";
467 StringBuilder message = new StringBuilder(HttpUtility.FormatPlainTextAsHtml((string) datarow[SR.Trace_Message]));
469 object errormessage = datarow["ErrorInfoMessage"];
470 object errorstack = datarow["ErrorInfoStack"];
471 if (!(errormessage is System.DBNull))
472 message.Append("<br>" + HttpUtility.FormatPlainTextAsHtml((string) errormessage));
473 if (!(errorstack is System.DBNull))
474 message.Append("<br>" + HttpUtility.FormatPlainTextAsHtml((string) errorstack));
476 tcell = AddCell(trow, message.ToString());
477 if (isErr) tcell.CssClass = "err";
479 tcell = AddCell(trow, FormatPotentialDouble(datarow[SR.Trace_From_First]));
480 if (isErr) tcell.CssClass = "err";
482 tcell = AddCell(trow, FormatPotentialDouble(datarow[SR.Trace_From_Last]));
483 if (isErr) tcell.CssClass = "err";
488 trow.CssClass = "alt";
496 private static string FormatPotentialDouble(object o) {
497 // pretty-prints double values (no scientific notation)
498 return (o is double) ? ((double)o).ToString("F6", CultureInfo.CurrentCulture) : o.ToString();
501 static internal Table CreateTable(DataTable datatable) {
502 return CreateTable(datatable, false);
505 static internal Table CreateTable(DataTable datatable, bool encodeSpaces) {
506 Table table = new Table();
507 table.Width = Unit.Percentage(100);
508 table.CellPadding = 0;
509 table.CellSpacing = 0;
511 if (datatable == null) return table;
519 // add a title for the table - same as table name
520 trow = AddRow(table);
521 tcell = AddHeaderCell(trow, "<h3><b>" + SR.GetString(datatable.TableName) + "</b></h3>");
522 tcell.CssClass = "alt";
523 tcell.ColumnSpan = 10;
524 tcell.HorizontalAlign = HorizontalAlign.Left;
526 // add the header information - same as column names
527 trow = AddRow(table);
528 trow.CssClass = "subhead";
529 trow.HorizontalAlign = HorizontalAlign.Left;
530 en = datatable.Columns.GetEnumerator();
531 while (en.MoveNext())
532 AddHeaderCell(trow, SR.GetString(((DataColumn) en.Current).ColumnName));
534 // now fill in the values, but don't display null values
535 en = datatable.Rows.GetEnumerator();
536 while (en.MoveNext()) {
537 cells = ((DataRow) en.Current).ItemArray;
538 trow = AddRow(table);
540 for (int i=0; i<cells.Length; i++) {
543 temp = HttpUtility.FormatPlainTextSpacesAsHtml(HttpUtility.HtmlEncode(cells[i].ToString()));
545 temp = HttpUtility.HtmlEncode(cells[i].ToString());
547 AddCell(trow, (temp.Length != 0) ? temp : " ");
552 trow.CssClass = "alt";
559 static internal Table CreateDetailsTable(DataTable datatable) {
560 Table table = new Table();
561 table.Width = Unit.Percentage(100);
562 table.CellPadding = 0;
563 table.CellSpacing = 0;
565 if (datatable == null) return table;
567 TableRow trow = AddRow(table);
568 TableCell tcell = AddHeaderCell(trow, "<h3><b>" + SR.GetString(SR.Trace_Request_Details) + "</b></h3>");
569 tcell.ColumnSpan = 10;
570 tcell.CssClass = "alt";
571 tcell.HorizontalAlign = HorizontalAlign.Left;
573 trow = AddRow(table);
574 trow.HorizontalAlign = HorizontalAlign.Left;
575 AddHeaderCell(trow, SR.GetString(SR.Trace_Session_Id) + ":");
576 AddCell(trow, HttpUtility.HtmlEncode(datatable.Rows[0][SR.Trace_Session_Id].ToString()));
577 AddHeaderCell(trow, SR.GetString(SR.Trace_Request_Type) + ":");
578 AddCell(trow, datatable.Rows[0][SR.Trace_Request_Type].ToString());
580 trow = AddRow(table);
581 trow.HorizontalAlign = HorizontalAlign.Left;
582 AddHeaderCell(trow, SR.GetString(SR.Trace_Time_of_Request) + ":");
583 AddCell(trow, datatable.Rows[0][SR.Trace_Time_of_Request].ToString());
584 AddHeaderCell(trow, SR.GetString(SR.Trace_Status_Code) + ":");
585 AddCell(trow, datatable.Rows[0][SR.Trace_Status_Code].ToString());
587 trow = AddRow(table);
588 trow.HorizontalAlign = HorizontalAlign.Left;
589 AddHeaderCell(trow, SR.GetString(SR.Trace_Request_Encoding) + ":");
590 AddCell(trow, datatable.Rows[0][SR.Trace_Request_Encoding].ToString());
591 AddHeaderCell(trow, SR.GetString(SR.Trace_Response_Encoding) + ":");
592 AddCell(trow, datatable.Rows[0][SR.Trace_Response_Encoding].ToString());