1 //------------------------------------------------------------------------------
2 // <copyright file="xml.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System
.Web
.UI
.WebControls
{
11 using System
.Collections
;
12 using System
.Collections
.Specialized
;
13 using System
.ComponentModel
;
14 using System
.ComponentModel
.Design
;
15 using System
.Diagnostics
.CodeAnalysis
;
16 using System
.Drawing
.Design
;
17 using System
.Globalization
;
19 using System
.Web
.Util
;
21 using System
.Web
.Caching
;
22 using System
.Web
.Hosting
;
23 using System
.Security
.Policy
;
26 using System
.Xml
.XPath
;
27 using System
.Security
.Permissions
;
29 public class XmlBuilder
: ControlBuilder
{
32 public override void AppendLiteralString(string s
) {}
35 public override Type
GetChildControlType(string tagName
, IDictionary attribs
) {
40 public override bool NeedsTagInnerText() { return true; }
43 [SuppressMessage("Microsoft.Security", "MSEC1220:ReviewDtdProcessingAssignment", Justification
= "Dtd processing is needed for back-compat, but is being done as safely as possible.")]
44 [SuppressMessage("Microsoft.Security.Xml", "CA3069:ReviewDtdProcessingAssignment", Justification
= "Dtd processing is needed for back-compat, but is being done as safely as possible.")]
45 public override void SetTagInnerText(string text
) {
46 if (!Util
.IsWhiteSpaceString(text
)) {
48 // Trim the initial whitespaces since XML is very picky (ASURT 58100)
49 int iFirstNonWhiteSpace
= Util
.FirstNonWhiteSpaceIndex(text
);
50 string textNoWS
= text
.Substring(iFirstNonWhiteSpace
);
52 // Update the line number to point to the correct line in the xml
53 // block (ASURT 58233).
54 Line
+= Util
.LineCount(text
, 0, iFirstNonWhiteSpace
);
56 // Parse the XML here just to cause a parse error in case it is
57 // malformed. It will be parsed again at runtime.
58 XmlDocument document
= new XmlDocument();
59 XmlReaderSettings readerSettings
= XmlUtils
.CreateXmlReaderSettings();
60 readerSettings
.LineNumberOffset
= Line
- 1;
62 // VSWhidbey 546662: XmlReader has different default settings than XmlTextReader which was used in Everett
63 readerSettings
.DtdProcessing
= DtdProcessing
.Parse
;
64 readerSettings
.CheckCharacters
= false;
66 XmlReader dataReader
= XmlUtils
.CreateXmlReader(new StringReader(textNoWS
), string.Empty
, readerSettings
);
69 document
.Load(dataReader
);
71 catch (XmlException e
) {
72 // Xml exception sometimes returns -1 for the line, in which case we ignore it.
73 if (e
.LineNumber
>= 0) {
80 base.AppendLiteralString(text
);
87 /// <para>[To be supplied.]</para>
90 DefaultProperty("DocumentSource"),
91 PersistChildren(false, true),
92 ControlBuilderAttribute(typeof(XmlBuilder
)),
93 Designer("System.Web.UI.Design.WebControls.XmlDesigner, " + AssemblyRef
.SystemDesign
)
95 public class Xml
: Control
{
97 private XPathNavigator _xpathNavigator
;
98 private XmlDocument _document
;
99 private XPathDocument _xpathDocument
;
100 #pragma warning disable 0618 // To avoid deprecation warning
101 private XslTransform _transform
;
102 #pragma warning restore 0618
103 private XslCompiledTransform _compiledTransform
;
104 private XsltArgumentList _transformArgumentList
;
105 private string _documentContent
;
106 private string _documentSource
;
107 private string _transformSource
;
109 const string identityXslStr
=
110 "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" +
111 "<xsl:template match=\"/\"> <xsl:copy-of select=\".\"/> </xsl:template> </xsl:stylesheet>";
113 #pragma warning disable 0618 // To avoid deprecation warning
114 static XslTransform _identityTransform
;
115 #pragma warning restore 0618
117 [SuppressMessage("Microsoft.Security", "MSEC1201:DoNotUseXslTransform", Justification
= "_identityTransform contents are trusted hard-coded string.")]
118 [SuppressMessage("Microsoft.Security.Xml", "CA3050:DoNotUseXslTransform", Justification
= "_identityTransform contents are trusted hard-coded string.")]
119 [SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification
= "_identityTransform contents are trusted hard-coded string.")]
120 [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification
= "_identityTransform contents are trusted hard-coded string.")]
121 [PermissionSet(SecurityAction
.Assert
, Unrestricted
= true)]
124 // Instantiate an identity transform, to be used whenever we need to output XML
125 XmlTextReader reader
= new XmlTextReader(new StringReader(identityXslStr
));
126 #pragma warning disable 0618 // To avoid deprecation warning
127 _identityTransform
= new XslTransform();
128 #pragma warning restore 0618
130 _identityTransform
.Load(reader
, null /*resolver*/, null /*evidence*/);
134 EditorBrowsable(EditorBrowsableState
.Never
),
136 public override string ClientID
{
138 return base.ClientID
;
143 EditorBrowsable(EditorBrowsableState
.Never
),
145 public override ControlCollection Controls
{
147 return base.Controls
;
153 /// <para>[To be supplied.]</para>
157 WebSysDescription(SR
.Xml_Document
),
158 DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
),
159 Obsolete("The recommended alternative is the XPathNavigator property. Create a System.Xml.XPath.XPathDocument and call CreateNavigator() to create an XPathNavigator. http://go.microsoft.com/fwlink/?linkid=14202"),
161 public XmlDocument Document
{
163 if (_document
== null) {
169 DocumentSource
= null;
170 _xpathDocument
= null;
171 _documentContent
= null;
178 /// <para>[To be supplied.]</para>
182 DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
),
183 WebSysDescription(SR
.Xml_DocumentContent
)
185 public String DocumentContent
{
187 return _documentContent
!= null ? _documentContent
: String
.Empty
;
191 _xpathDocument
= null;
192 _xpathNavigator
= null;
193 _documentContent
= value;
196 ViewState
["OriginalContent"] = null;
203 /// <para>[To be supplied.]</para>
206 WebCategory("Behavior"),
208 Editor("System.Web.UI.Design.XmlUrlEditor, " + AssemblyRef
.SystemDesign
, typeof(UITypeEditor
)),
210 WebSysDescription(SR
.Xml_DocumentSource
)
212 public String DocumentSource
{
214 return (_documentSource
== null) ? String
.Empty
: _documentSource
;
218 _xpathDocument
= null;
219 _documentContent
= null;
220 _xpathNavigator
= null;
221 _documentSource
= value;
228 EditorBrowsable(EditorBrowsableState
.Never
),
230 public override bool EnableTheming
{
235 throw new NotSupportedException(SR
.GetString(SR
.NoThemingSupport
, this.GetType().Name
));
242 EditorBrowsable(EditorBrowsableState
.Never
),
244 public override string SkinID
{
249 throw new NotSupportedException(SR
.GetString(SR
.NoThemingSupport
, this.GetType().Name
));
255 /// <para>[To be supplied.]</para>
259 WebSysDescription(SR
.Xml_Transform
),
260 DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)
262 #pragma warning disable 0618 // To avoid deprecation warning
263 public XslTransform Transform
{
264 #pragma warning restore 0618
266 return XmlUtils
.GetXslTransform(_transform
);
269 if (XmlUtils
.GetXslTransform(value) != null) {
270 // Setting this property will nullify _transform, so do it first.
271 TransformSource
= null;
279 /// <para>[To be supplied.]</para>
283 WebSysDescription(SR
.Xml_TransformArgumentList
),
284 DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)
286 public XsltArgumentList TransformArgumentList
{
288 return _transformArgumentList
;
291 _transformArgumentList
= value;
297 /// <para>[To be supplied.]</para>
300 WebCategory("Behavior"),
302 Editor("System.Web.UI.Design.XslUrlEditor, " + AssemblyRef
.SystemDesign
, typeof(UITypeEditor
)),
303 WebSysDescription(SR
.Xml_TransformSource
),
305 public String TransformSource
{
307 return (_transformSource
== null) ? String
.Empty
: _transformSource
;
311 _transformSource
= value;
320 WebSysDescription(SR
.Xml_XPathNavigator
),
321 DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)
323 public XPathNavigator XPathNavigator
{
325 return _xpathNavigator
;
328 DocumentSource
= null;
329 _xpathDocument
= null;
330 _documentContent
= null;
332 _xpathNavigator
= value;
337 [SuppressMessage("Microsoft.Security", "MSEC1218:ReviewWebControlForSet_DocumentContent", Justification
= "Legacy code that trusts our developer input. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
338 [SuppressMessage("Microsoft.Security.Xml", "CA3067:ReviewWebControlForSet_DocumentContent", Justification
= "Legacy code that trusts our developer input. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
339 protected override void AddParsedSubObject(object obj
) {
340 if (obj
is LiteralControl
) {
341 // Trim the initial whitespaces since XML is very picky (related to ASURT 58100)
342 string text
= ((LiteralControl
)obj
).Text
;
344 int iFirstNonWhiteSpace
= Util
.FirstNonWhiteSpaceIndex(text
);
345 DocumentContent
= text
.Substring(iFirstNonWhiteSpace
);
348 ViewState
["OriginalContent"] = text
;
352 throw new HttpException(SR
.GetString(SR
.Cannot_Have_Children_Of_Type
, "Xml", obj
.GetType().Name
.ToString(CultureInfo
.InvariantCulture
)));
356 protected override ControlCollection
CreateControlCollection() {
357 return new EmptyControlCollection(this);
361 EditorBrowsable(EditorBrowsableState
.Never
),
363 public override Control
FindControl(string id
) {
364 return base.FindControl(id
);
371 EditorBrowsable(EditorBrowsableState
.Never
),
373 public override void Focus() {
374 throw new NotSupportedException(SR
.GetString(SR
.NoFocusSupport
, this.GetType().Name
));
377 [SecurityPermission(SecurityAction
.Demand
, Unrestricted
= true)]
378 protected override IDictionary
GetDesignModeState() {
379 IDictionary designModeState
= new HybridDictionary();
380 designModeState
["OriginalContent"] = ViewState
["OriginalContent"];
382 return designModeState
;
386 EditorBrowsable(EditorBrowsableState
.Never
),
388 public override bool HasControls() {
389 return base.HasControls();
392 private void LoadTransformFromSource() {
394 // We're done if we already have a transform
395 if (_transform
!= null)
398 if (String
.IsNullOrEmpty(_transformSource
) || _transformSource
.Trim().Length
== 0)
401 // First, figure out if it's a physical or virtual path
402 VirtualPath virtualPath
;
404 ResolvePhysicalOrVirtualPath(_transformSource
, out virtualPath
, out physicalPath
);
406 CacheStoreProvider cacheInternal
= HttpRuntime
.Cache
.InternalCache
;
407 string key
= CacheInternal
.PrefixLoadXPath
+ ((physicalPath
!= null) ?
408 physicalPath
: virtualPath
.VirtualPathString
);
410 object xform
= cacheInternal
.Get(key
);
413 Debug
.Trace("XmlControl", "Xsl Transform not found in cache (" + _transformSource
+ ")");
415 // Get the stream, and open the doc
416 CacheDependency dependency
;
417 using (Stream stream
= OpenFileAndGetDependency(virtualPath
, physicalPath
, out dependency
)) {
419 // If we don't have a physical path, call MapPath to get one, in order to pass it as
420 // the baseUri to XmlTextReader. In pure VirtualPathProvider scenarios, it won't
421 // help much, but it allows the default case to have relative references (VSWhidbey 545322)
422 if (physicalPath
== null)
423 physicalPath
= virtualPath
.MapPath();
425 // XslCompiledTransform for some reason wants to completely re-create an internal XmlReader
426 // from scratch. In doing so, it does not respect all the settings of XmlTextReader. So we want
427 // to be sure to specifically use XmlReader here so our settings on it will be respected by the
428 // XslCompiledTransform.
429 XmlReader xmlReader
= XmlUtils
.CreateXmlReader(stream
, physicalPath
);
430 _transform
= XmlUtils
.CreateXslTransform(xmlReader
);
431 if (_transform
== null) {
432 _compiledTransform
= XmlUtils
.CreateXslCompiledTransform(xmlReader
);
436 // Cache it, but only if we got a dependency
437 if (dependency
!= null) {
439 cacheInternal
.Insert(key
, ((_compiledTransform
== null) ? (object)_transform
: (object)_compiledTransform
),
440 new CacheInsertOptions() { Dependencies = dependency }
);
445 Debug
.Trace("XmlControl", "XslTransform found in cache (" + _transformSource
+ ")");
447 _compiledTransform
= xform
as XslCompiledTransform
;
448 if (_compiledTransform
== null) {
449 #pragma warning disable 0618 // To avoid deprecation warning
450 _transform
= (XslTransform
)xform
;
451 #pragma warning restore 0618
456 private void LoadXmlDocument() {
458 Debug
.Assert(_xpathDocument
== null && _document
== null && _xpathNavigator
== null);
460 if (!String
.IsNullOrEmpty(_documentContent
)) {
461 _document
= XmlUtils
.CreateXmlDocumentFromContent(_documentContent
);
465 if (String
.IsNullOrEmpty(_documentSource
))
468 // Make it absolute and check security
469 string physicalPath
= MapPathSecure(_documentSource
);
471 CacheStoreProvider cacheInternal
= System
.Web
.HttpRuntime
.Cache
.InternalCache
;
472 string key
= CacheInternal
.PrefixLoadXml
+ physicalPath
;
474 _document
= (XmlDocument
) cacheInternal
.Get(key
);
476 if (_document
== null) {
477 Debug
.Trace("XmlControl", "XmlDocument not found in cache (" + _documentSource
+ ")");
479 CacheDependency dependency
;
480 using (Stream stream
= OpenFileAndGetDependency(null, physicalPath
, out dependency
)) {
482 _document
= new XmlDocument();
483 _document
.Load(XmlUtils
.CreateXmlReader(stream
, physicalPath
));
484 cacheInternal
.Insert(key
, _document
, new CacheInsertOptions() { Dependencies = dependency }
);
488 Debug
.Trace("XmlControl", "XmlDocument found in cache (" + _documentSource
+ ")");
493 // Always return a clone of the cached copy
494 _document
= (XmlDocument
)_document
.CloneNode(true/*deep*/);
498 private void LoadXPathDocument() {
500 Debug
.Assert(_xpathDocument
== null && _document
== null && _xpathNavigator
== null);
502 if (!String
.IsNullOrEmpty(_documentContent
)) {
503 _xpathDocument
= XmlUtils
.CreateXPathDocumentFromContent(_documentContent
);
507 if (String
.IsNullOrEmpty(_documentSource
))
510 // First, figure out if it's a physical or virtual path
511 VirtualPath virtualPath
;
513 ResolvePhysicalOrVirtualPath(_documentSource
, out virtualPath
, out physicalPath
);
515 CacheStoreProvider cacheInternal
= HttpRuntime
.Cache
.InternalCache
;
516 string key
= CacheInternal
.PrefixLoadXPath
+ ((physicalPath
!= null) ?
517 physicalPath
: virtualPath
.VirtualPathString
);
519 _xpathDocument
= (XPathDocument
)cacheInternal
.Get(key
);
520 if (_xpathDocument
== null) {
521 Debug
.Trace("XmlControl", "XPathDocument not found in cache (" + _documentSource
+ ")");
523 // Get the stream, and open the doc
524 CacheDependency dependency
;
525 using (Stream stream
= OpenFileAndGetDependency(virtualPath
, physicalPath
, out dependency
)) {
526 // The same comments as in LoadTransformFromSource() (VSWhidbey 545322, 546662)
527 if (physicalPath
== null) {
528 physicalPath
= virtualPath
.MapPath();
531 _xpathDocument
= new XPathDocument(XmlUtils
.CreateXmlReader(stream
, physicalPath
));
534 // Cache it, but only if we got a dependency
535 if (dependency
!= null) {
537 cacheInternal
.Insert(key
, _xpathDocument
, new CacheInsertOptions() { Dependencies = dependency }
);
542 Debug
.Trace("XmlControl", "XPathDocument found in cache (" + _documentSource
+ ")");
548 /// <para>[To be supplied.]</para>
550 [SuppressMessage("Microsoft.Security", "MSEC1204:UseSecureXmlResolver", Justification
= "Legacy code that trusts our developer input. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
551 protected internal override void Render(HtmlTextWriter output
)
554 // If we don't already have an XmlDocument or an XPathNavigator, load am XPathDocument (which is faster)
555 if ((_document
== null) && (_xpathNavigator
== null)) {
559 LoadTransformFromSource();
561 // Abort if nothing has been loaded
562 if (_document
== null && _xpathDocument
== null && _xpathNavigator
== null) {
566 // If we don't have a transform, use the identity transform, which
567 // simply renders the XML.
568 if (_transform
== null)
569 _transform
= _identityTransform
;
571 // Pass a resolver in full trust, to support certain XSL scenarios (ASURT 141427)
572 XmlUrlResolver xr
= null;
573 if (HttpRuntime
.HasUnmanagedPermission()) {
574 xr
= new XmlUrlResolver();
577 IXPathNavigable doc
= null;
578 if (_document
!= null) {
580 } else if (_xpathNavigator
!= null) {
581 doc
= _xpathNavigator
;
583 doc
= _xpathDocument
;
586 if (_compiledTransform
!= null) {
587 XmlWriter writer
= XmlWriter
.Create(output
);
588 _compiledTransform
.Transform(doc
, _transformArgumentList
, writer
, null);
590 _transform
.Transform(doc
, _transformArgumentList
, output
, xr
);