Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Web.Services / System / Web / Services / Discovery / DiscoveryDocumentReference.cs
blob097e213372828f8fcdfaa5f181438d2f4cb119d6
1 //------------------------------------------------------------------------------
2 // <copyright file="DiscoveryDocumentReference.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
7 namespace System.Web.Services.Discovery {
9 using System;
10 using System.Net;
11 using System.Xml;
12 using System.Diagnostics;
13 using System.IO;
14 using System.Xml.Serialization;
15 using System.Web.Services.Protocols;
16 using System.Web.Services.Configuration;
17 using System.Text;
18 using System.Globalization;
19 using System.Threading;
20 using System.Collections;
21 using System.Web.Services.Diagnostics;
23 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference"]/*' />
24 /// <devdoc>
25 /// <para>[To be supplied.]</para>
26 /// </devdoc>
27 [XmlRoot("discoveryRef", Namespace = DiscoveryDocument.Namespace)]
28 public sealed class DiscoveryDocumentReference : DiscoveryReference {
30 private string reference;
32 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.DiscoveryDocumentReference"]/*' />
33 /// <devdoc>
34 /// <para>[To be supplied.]</para>
35 /// </devdoc>
36 public DiscoveryDocumentReference() {
39 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.DiscoveryDocumentReference1"]/*' />
40 /// <devdoc>
41 /// <para>[To be supplied.]</para>
42 /// </devdoc>
43 public DiscoveryDocumentReference(string href) {
44 Ref = href;
47 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.Ref"]/*' />
48 /// <devdoc>
49 /// <para>[To be supplied.]</para>
50 /// </devdoc>
51 [XmlAttribute("ref")]
52 public string Ref {
53 get {
54 return reference == null ? "" : reference;
56 set {
57 reference = value;
61 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.DefaultFilename"]/*' />
62 /// <devdoc>
63 /// <para>[To be supplied.]</para>
64 /// </devdoc>
65 [XmlIgnore]
66 public override string DefaultFilename {
67 get {
68 string filename = FilenameFromUrl(Url);
69 return Path.ChangeExtension(filename, ".disco"); // [Microsoft] change default extension
73 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.Document"]/*' />
74 /// <devdoc>
75 /// <para>[To be supplied.]</para>
76 /// </devdoc>
77 [XmlIgnore]
78 public DiscoveryDocument Document {
79 get {
80 if (ClientProtocol == null)
81 throw new InvalidOperationException(Res.GetString(Res.WebMissingClientProtocol));
82 object document = ClientProtocol.Documents[Url];
83 if (document == null) {
84 Resolve();
85 document = ClientProtocol.Documents[Url];
87 DiscoveryDocument discoDocument = document as DiscoveryDocument;
88 if (discoDocument == null) {
89 throw new InvalidOperationException(Res.GetString(Res.WebInvalidDocType,
90 typeof(DiscoveryDocument).FullName,
91 document == null ? string.Empty : document.GetType().FullName,
92 Url));
94 return discoDocument;
98 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.WriteDocument"]/*' />
99 /// <devdoc>
100 /// <para>[To be supplied.]</para>
101 /// </devdoc>
102 public override void WriteDocument(object document, Stream stream) {
103 WebServicesSection.Current.DiscoveryDocumentSerializer.Serialize(new StreamWriter(stream, new UTF8Encoding(false)), document);
106 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.ReadDocument"]/*' />
107 /// <devdoc>
108 /// <para>[To be supplied.]</para>
109 /// </devdoc>
110 public override object ReadDocument(Stream stream) {
111 return WebServicesSection.Current.DiscoveryDocumentSerializer.Deserialize(stream);
114 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.Url"]/*' />
115 /// <devdoc>
116 /// <para>[To be supplied.]</para>
117 /// </devdoc>
118 [XmlIgnore]
119 public override string Url {
120 get { return Ref; }
121 set { Ref = value; }
124 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.GetDocumentNoParse"]/*' />
125 /// <devdoc>
126 /// Retrieves a discovery document from Url, either out of the ClientProtocol
127 /// or from a stream. Does not
128 /// </devdoc>
129 private static DiscoveryDocument GetDocumentNoParse(ref string url, DiscoveryClientProtocol client) {
130 DiscoveryDocument d = (DiscoveryDocument) client.Documents[url];
131 if (d != null) {
132 return d;
135 string contentType = null;
137 Stream stream = client.Download(ref url, ref contentType);
138 try {
139 XmlTextReader reader = new XmlTextReader(new StreamReader(stream, RequestResponseUtils.GetEncoding(contentType)));
140 reader.WhitespaceHandling = WhitespaceHandling.Significant;
141 reader.XmlResolver = null;
142 reader.DtdProcessing = DtdProcessing.Prohibit;
143 if (!DiscoveryDocument.CanRead(reader)) {
144 // there is no discovery document at this location
145 ArgumentException exception = new ArgumentException(Res.GetString(Res.WebInvalidFormat));
146 throw new InvalidOperationException(Res.GetString(Res.WebMissingDocument, url), exception);
148 return DiscoveryDocument.Read(reader);
150 finally {
151 stream.Close();
155 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.Resolve"]/*' />
156 /// <devdoc>
157 /// <para>[To be supplied.]</para>
158 /// </devdoc>
159 protected internal override void Resolve(string contentType, Stream stream) {
160 DiscoveryDocument document = null;
162 if (ContentType.IsHtml(contentType)) {
163 string newRef = LinkGrep.SearchForLink(stream);
164 if (newRef != null) {
165 string newUrl = UriToString(Url, newRef);
166 document = GetDocumentNoParse(ref newUrl, ClientProtocol);
167 Url = newUrl;
169 else
170 throw new InvalidContentTypeException(Res.GetString(Res.WebInvalidContentType, contentType), contentType);
173 if (document == null) { // probably xml...
174 XmlTextReader reader = new XmlTextReader(new StreamReader(stream, RequestResponseUtils.GetEncoding(contentType)));
175 reader.XmlResolver = null;
176 reader.WhitespaceHandling = WhitespaceHandling.Significant;
177 reader.DtdProcessing = DtdProcessing.Prohibit;
178 if (DiscoveryDocument.CanRead(reader)) {
179 // it's a discovery document, so just read it.
180 document = DiscoveryDocument.Read(reader);
182 else {
183 // check out the processing instructions before the first tag. if any of them
184 // match the form specified in the DISCO spec, save the href.
185 stream.Position = 0;
186 XmlTextReader newReader = new XmlTextReader(new StreamReader(stream, RequestResponseUtils.GetEncoding(contentType)));
187 newReader.XmlResolver = null;
188 newReader.DtdProcessing = DtdProcessing.Prohibit;
189 while (newReader.NodeType != XmlNodeType.Element) {
190 if (newReader.NodeType == XmlNodeType.ProcessingInstruction) {
191 // manually parse the PI contents since XmlTextReader won't automatically do it
192 StringBuilder sb = new StringBuilder("<pi ");
193 sb.Append(newReader.Value);
194 sb.Append("/>");
195 XmlTextReader piReader = new XmlTextReader(new StringReader(sb.ToString()));
196 piReader.XmlResolver = null;
197 piReader.DtdProcessing = DtdProcessing.Prohibit;
198 piReader.Read();
199 string type = piReader["type"];
200 string alternate = piReader["alternate"];
201 string href = piReader["href"];
202 if (type != null && ContentType.MatchesBase(type, ContentType.TextXml)
203 && alternate != null && string.Compare(alternate, "yes", StringComparison.OrdinalIgnoreCase) == 0
204 && href != null) {
205 // we got a PI with the right attributes
207 // there is a link to a discovery document. follow it after fully qualifying it.
208 string newUrl = UriToString(Url, href);
209 document = GetDocumentNoParse(ref newUrl, ClientProtocol);
210 Url = newUrl;
211 break;
214 newReader.Read();
219 if (document == null) {
220 // there is no discovery document at this location
221 Exception exception;
222 if (ContentType.IsXml(contentType)) {
223 exception = new ArgumentException(Res.GetString(Res.WebInvalidFormat));
225 else {
226 exception = new InvalidContentTypeException(Res.GetString(Res.WebInvalidContentType, contentType), contentType);
228 throw new InvalidOperationException(Res.GetString(Res.WebMissingDocument, Url), exception);
231 ClientProtocol.References[Url] = this;
232 ClientProtocol.Documents[Url] = document;
234 foreach (object o in document.References) {
235 if (o is DiscoveryReference) {
236 DiscoveryReference r = (DiscoveryReference) o;
237 if (r.Url.Length == 0) {
238 throw new InvalidOperationException(Res.GetString(Res.WebEmptyRef, r.GetType().FullName, Url));
240 r.Url = UriToString(Url, r.Url);
241 //All inheritors of DiscoveryReference that got URIs relative
242 //to Ref property should adjust them like ContractReference does here.
243 ContractReference cr = r as ContractReference;
244 if ( (cr != null) && (cr.DocRef != null) ) {
245 cr.DocRef = UriToString(Url, cr.DocRef);
247 r.ClientProtocol = ClientProtocol;
248 ClientProtocol.References[r.Url] = r;
250 else
251 ClientProtocol.AdditionalInformation.Add(o);
254 return;
257 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.ResolveAll"]/*' />
258 /// <devdoc>
259 /// <para>[To be supplied.]</para>
260 /// </devdoc>
261 public void ResolveAll() {
262 ResolveAll(true);
265 internal void ResolveAll(bool throwOnError) {
266 try {
267 Resolve();
269 catch (Exception e) {
270 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
271 throw;
273 if (throwOnError)
274 throw;
276 if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "ResolveAll", e);
278 // can't continue, because we couldn't find a document.
279 return;
282 foreach (object o in Document.References) {
283 DiscoveryDocumentReference r = o as DiscoveryDocumentReference;
284 if (r == null)
285 continue;
286 if (ClientProtocol.Documents[r.Url] != null) {
287 continue;
289 r.ClientProtocol = ClientProtocol;
290 r.ResolveAll(throwOnError);