1 //------------------------------------------------------------------------------
2 // <copyright file="DiscoveryReference.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 namespace System.Web.Services.Discovery {
8 
9     using System;
10     using System.Xml.Serialization;
11     using System.Text.RegularExpressions;
12     using System.IO;
13     using System.Text;
14     using System.Threading;
15     using System.Collections;
16     using System.Diagnostics;
17     using System.Web.Services.Diagnostics;
18 
19     /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference"]/*' />
20     /// <devdoc>
21     ///    <para>[To be supplied.]</para>
22     /// </devdoc>
23     public abstract class DiscoveryReference {
24 
25         private DiscoveryClientProtocol clientProtocol;
26 
27         /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.ClientProtocol"]/*' />
28         /// <devdoc>
29         ///    <para>[To be supplied.]</para>
30         /// </devdoc>
31         [XmlIgnore]
32         public DiscoveryClientProtocol ClientProtocol {
33             get { return clientProtocol; }
34             set { clientProtocol = value; }
35         }
36 
37         /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.DefaultFilename"]/*' />
38         /// <devdoc>
39         ///    <para>[To be supplied.]</para>
40         /// </devdoc>
41         [XmlIgnore]
42         public virtual string DefaultFilename {
43             get {
44                 return FilenameFromUrl(Url);
45             }
46         }
47 
48         /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.WriteDocument"]/*' />
49         /// <devdoc>
50         ///    <para>[To be supplied.]</para>
51         /// </devdoc>
WriteDocument(object document, Stream stream)52         public abstract void WriteDocument(object document, Stream stream);
53         /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.ReadDocument"]/*' />
54         /// <devdoc>
55         ///    <para>[To be supplied.]</para>
56         /// </devdoc>
ReadDocument(Stream stream)57         public abstract object ReadDocument(Stream stream);
58 
59         /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.Url"]/*' />
60         /// <devdoc>
61         ///    <para>[To be supplied.]</para>
62         /// </devdoc>
63         [XmlIgnore]
64         public abstract string Url {
65             get;
66             set;
67         }
68 
LoadExternals(Hashtable loadedExternals)69         internal virtual void LoadExternals(Hashtable loadedExternals) {
70         }
71 
72         /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.FilenameFromUrl"]/*' />
73         /// <devdoc>
74         ///    <para>[To be supplied.]</para>
75         /// </devdoc>
FilenameFromUrl(string url)76         public static string FilenameFromUrl(string url) {
77             // get everything after the last /, not including the one at the end of the string
78             int lastSlash = url.LastIndexOf('/', url.Length - 1);
79             if (lastSlash >= 0) url = url.Substring(lastSlash + 1);
80 
81             // get everything up to the first dot (the filename)
82             int firstDot = url.IndexOf('.');
83             if (firstDot >= 0) url = url.Substring(0, firstDot);
84 
85             // make sure we don't include the question mark and stuff that follows it
86             int question = url.IndexOf('?');
87             if (question >= 0) url = url.Substring(0, question);
88             if (url == null || url.Length == 0)
89                 return "item";
90             return MakeValidFilename(url);
91         }
92 
FindChar(char ch, char[] chars)93         private static bool FindChar(char ch, char[] chars) {
94             for (int i = 0; i < chars.Length; i++) {
95                 if (ch == chars[i])
96                     return true;
97             }
98             return false;
99         }
100 
MakeValidFilename(string filename)101         internal static string MakeValidFilename(string filename) {
102             if (filename == null)
103                 return null;
104 
105             StringBuilder sb = new StringBuilder(filename.Length);
106             for (int i = 0; i < filename.Length; i++) {
107                 char c = filename[i];
108                 if (!FindChar(c, Path.InvalidPathChars))
109                     sb.Append(c);
110             }
111             string name = sb.ToString();
112             if (name.Length == 0)
113                 name = "item";
114 
115             return Path.GetFileName(name);
116         }
117 
118         /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.Resolve"]/*' />
119         /// <devdoc>
120         ///    <para>[To be supplied.]</para>
121         /// </devdoc>
Resolve()122         public void Resolve() {
123             if (ClientProtocol == null)
124                 throw new InvalidOperationException(Res.GetString(Res.WebResolveMissingClientProtocol));
125 
126             if (ClientProtocol.Documents[Url] != null)
127                 return;
128             if (ClientProtocol.InlinedSchemas[Url] != null)
129                 return;
130 
131             string newUrl = Url;
132             string oldUrl = Url;
133             string contentType = null;
134             Stream stream = ClientProtocol.Download(ref newUrl, ref contentType);
135             if (ClientProtocol.Documents[newUrl] != null) {
136                 Url = newUrl;
137                 return;
138             }
139             try {
140                 Url = newUrl;
141                 Resolve(contentType, stream);
142             }
143             catch {
144                 Url = oldUrl;
145                 throw;
146             }
147             finally {
148                 stream.Close();
149             }
150         }
151 
AttemptResolve(string contentType, Stream stream)152         internal Exception AttemptResolve(string contentType, Stream stream) {
153             try {
154                 Resolve(contentType, stream);
155                 return null;
156             }
157             catch (Exception e) {
158                 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
159                     throw;
160                 }
161                 if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "AttemptResolve", e);
162                 return e;
163             }
164         }
165 
166         /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.Resolve1"]/*' />
167         /// <devdoc>
168         ///    <para>[To be supplied.]</para>
169         /// </devdoc>
Resolve(string contentType, Stream stream)170         protected internal abstract void Resolve(string contentType, Stream stream);
171 
UriToString(string baseUrl, string relUrl)172         internal static string UriToString(string baseUrl, string relUrl) {
173             return (new Uri(new Uri(baseUrl), relUrl)).GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped);
174         }
175     }
176 }
177