[System.Net] Add support for .pac proxy config scripts on mac
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Configuration / WebServicesConfigurationSectionHandler.cs
1 //
2 // System.Web.Services.Configuration.WebServicesConfigurationSectionHandler
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2003 Ximian, Inc (http://www.ximian.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.Collections;
33 using System.Configuration;
34 using System.Xml;
35
36 namespace System.Web.Services.Configuration
37 {
38         [Flags]
39         enum WSProtocol
40         {
41                 HttpSoap = 1,
42                 HttpPost = 1 << 1,
43                 HttpGet =  1 << 2,
44                 Documentation = 1 << 3,
45                 HttpSoap12 = 1 << 4,
46                 HttpPostLocalhost = 1 << 5,
47                 AnyHttpSoap = HttpSoap | HttpSoap12,
48                 All = 0xFF
49         }
50         
51         class WSConfig
52         {
53 #if !TARGET_JVM
54                 volatile static WSConfig instance;
55 #else
56                 static WSConfig instance {
57                         get {
58                                 return (WSConfig)AppDomain.CurrentDomain.GetData("WSConfig.instance");
59                         }
60                         set {
61                                 AppDomain.CurrentDomain.SetData("WSConfig.instance", value);
62                         }
63                 }
64
65 #endif
66                 WSProtocol protocols;
67                 string wsdlHelpPage;
68                 string filePath;
69                 ArrayList extensionTypes = new ArrayList();
70                 ArrayList extensionImporterTypes = new ArrayList();
71                 ArrayList extensionReflectorTypes = new ArrayList();
72                 ArrayList formatExtensionTypes = new ArrayList();
73                 static readonly object lockobj = new object ();
74                 
75                 public WSConfig (WSConfig parent, object context)
76                 {
77                         if (parent == null)
78                                 return;
79                         
80                         protocols = parent.protocols;
81                         wsdlHelpPage = parent.wsdlHelpPage;
82                         if (wsdlHelpPage != null)
83                                 filePath = parent.filePath;
84                         else
85                                 filePath = context as string;
86                 }
87                 
88                 static WSProtocol ParseProtocol (string protoName, out string error)
89                 {
90                         WSProtocol proto;
91                         error = null;
92
93 #if ONLY_1_1
94                         switch (protoName) {
95                                 case "HttpSoap1.2":
96                                         protoName = "HttpSoap12";
97                                         break;
98                                 case "HttpSoap12":
99                                         protoName = null;
100                                         break;
101                         }
102 #endif
103                         try {
104                                 proto = (WSProtocol) Enum.Parse (typeof (WSProtocol), protoName);
105                         } catch {
106                                 error = "Invalid protocol name";
107                                 return 0;
108                         }
109
110                         return proto;
111                 }
112
113                 // Methods to modify configuration values
114                 public bool AddProtocol (string protoName, out string error)
115                 {
116                         if (protoName == "All") {
117                                 error = "Invalid protocol name";
118                                 return false;
119                         }
120
121                         WSProtocol proto = ParseProtocol (protoName, out error);
122                         if (error != null)
123                                 return false;
124
125                         protocols |= proto;
126                         return true;
127                 }
128
129                 public bool RemoveProtocol (string protoName, out string error)
130                 {
131                         if (protoName == "All") {
132                                 error = "Invalid protocol name";
133                                 return false;
134                         }
135
136                         WSProtocol proto = ParseProtocol (protoName, out error);
137                         if (error != null)
138                                 return false;
139
140                         protocols &= ~proto;
141                         return true;
142                 }
143
144                 public void ClearProtocol ()
145                 {
146                         protocols = 0;
147                 }
148
149                 // Methods to query/get configuration
150                 public static bool IsSupported (WSProtocol proto)
151                 {
152                         return ((Instance.protocols & proto) == proto && (proto != 0) && (proto != WSProtocol.All));
153                 }
154
155                 // Properties
156                 public string WsdlHelpPage {
157                         get { return wsdlHelpPage; }
158                         set { wsdlHelpPage = value; }
159                 }
160
161                 public string ConfigFilePath {
162                         get { return filePath; }
163                         set { filePath = value; }
164                 }
165
166                 static public WSConfig Instance {
167                         get {
168                                 //TODO: use HttpContext to get the configuration
169                                 if (instance != null)
170                                         return instance;
171
172                                 lock (lockobj) {
173                                         if (instance != null)
174                                                 return instance;
175
176                                         instance = (WSConfig) ConfigurationSettings.GetConfig ("system.web/webServices");
177                                 }
178
179                                 return instance;
180                         }
181                 }
182
183                 public ArrayList ExtensionTypes {
184                         get { return extensionTypes; }
185                 }
186
187                 public ArrayList ExtensionImporterTypes {
188                         get { return extensionImporterTypes; }
189                 }
190                 
191                 public ArrayList ExtensionReflectorTypes {
192                         get { return extensionReflectorTypes; }
193                 }
194                 
195                 public ArrayList FormatExtensionTypes {
196                         get { return formatExtensionTypes; }
197                 }
198                 
199         }
200         
201         enum WSExtensionGroup
202         {
203                 High,
204                 Low
205         }
206         
207         class WSExtensionConfig
208         {
209                 Type type;
210                 int priority;
211                 WSExtensionGroup group;
212
213                 public Exception SetType (string typeName)
214                 {
215                         Exception exc = null;
216                         
217                         try {
218                                 type = Type.GetType (typeName, true);
219                         } catch (Exception e) {
220                                 exc = e;
221                         }
222
223                         return exc;
224                 }
225                 
226                 public Exception SetPriority (string prio)
227                 {
228                         if (prio == null || prio == "")
229                                 return null;
230
231                         Exception exc = null;
232                         try {
233                                 priority = Int32.Parse (prio);
234                         } catch (Exception e) {
235                                 exc = e;
236                         }
237
238                         return exc;
239                 }
240                 
241                 public Exception SetGroup (string grp)
242                 {
243                         if (grp == null || grp == "")
244                                 return null;
245
246                         Exception exc = null;
247                         try {
248                                 group = (WSExtensionGroup) Int32.Parse (grp);
249                                 if (group < WSExtensionGroup.High || group > WSExtensionGroup.Low)
250                                         throw new ArgumentOutOfRangeException ("group", "Must be 0 or 1");
251                         } catch (Exception e) {
252                                 exc = e;
253                         }
254
255                         return exc;
256                 }
257                 
258                 // Getters
259                 public Type Type {
260                         get { return type; }
261                 }
262
263                 public int Priority {
264                         get { return priority; }
265                 }
266
267                 public WSExtensionGroup Group {
268                         get { return group; }
269                 }
270         }
271         
272         class WebServicesConfigurationSectionHandler : IConfigurationSectionHandler
273         {
274                 public object Create (object parent, object context, XmlNode section)
275                 {
276                         WSConfig config = new WSConfig (parent as WSConfig, context);
277
278                         if (section.Attributes != null && section.Attributes.Count != 0)
279                                 ThrowException ("Unrecognized attribute", section);
280
281                         XmlNodeList nodes = section.ChildNodes;
282                         foreach (XmlNode child in nodes) {
283                                 XmlNodeType ntype = child.NodeType;
284                                 if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
285                                         continue;
286
287                                 if (ntype != XmlNodeType.Element)
288                                         ThrowException ("Only elements allowed", child);
289                                 
290                                 string name = child.Name;
291                                 if (name == "protocols") {
292                                         ConfigProtocols (child, config);
293                                         continue;
294                                 }
295
296                                 if (name == "soapExtensionTypes") {
297                                         ConfigSoapExtensionTypes (child, config.ExtensionTypes);
298                                         continue;
299                                 }
300
301                                 if (name == "soapExtensionReflectorTypes") {
302                                         ConfigSoapExtensionTypes (child, config.ExtensionReflectorTypes);
303                                         continue;
304                                 }
305
306                                 if (name == "soapExtensionImporterTypes") {
307                                         ConfigSoapExtensionTypes (child, config.ExtensionImporterTypes);
308                                         continue;
309                                 }
310
311                                 if (name == "serviceDescriptionFormatExtensionTypes") {
312                                         ConfigFormatExtensionTypes (child, config);
313                                         continue;
314                                 }
315
316                                 if (name == "wsdlHelpGenerator") {
317                                         string href = AttValue ("href", child, false);
318                                         if (child.Attributes != null && child.Attributes.Count != 0)
319                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
320
321                                         config.ConfigFilePath = context as string;
322                                         config.WsdlHelpPage = href;
323                                         continue;
324                                 }
325
326                                 ThrowException ("Unexpected element", child);
327                         }
328
329                         return config;
330                 }
331
332                 static void ConfigProtocols (XmlNode section, WSConfig config)
333                 {
334                         if (section.Attributes != null && section.Attributes.Count != 0)
335                                 ThrowException ("Unrecognized attribute", section);
336
337                         XmlNodeList nodes = section.ChildNodes;
338                         foreach (XmlNode child in nodes) {
339                                 XmlNodeType ntype = child.NodeType;
340                                 if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
341                                         continue;
342
343                                 if (ntype != XmlNodeType.Element)
344                                         ThrowException ("Only elements allowed", child);
345                                 
346                                 string name = child.Name;
347                                 string error;
348                                 if (name == "add") {
349                                         string protoName = AttValue ("name", child, false);
350                                         if (child.Attributes != null && child.Attributes.Count != 0)
351                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
352
353                                         if (!config.AddProtocol (protoName, out error))
354                                                 ThrowException (error, child);
355                                         
356                                         continue;
357                                 }
358
359                                 if (name == "remove") {
360                                         string protoName = AttValue ("name", child, false);
361                                         if (child.Attributes != null && child.Attributes.Count != 0)
362                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
363
364                                         if (!config.RemoveProtocol (protoName, out error))
365                                                 ThrowException (error, child);
366                                         
367                                         continue;
368                                 }
369
370                                 if (name == "clear") {
371                                         if (child.Attributes != null && child.Attributes.Count != 0)
372                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
373
374                                         config.ClearProtocol ();
375                                         continue;
376                                 }
377
378                                 ThrowException ("Unexpected element", child);
379                         }
380                 }
381                 
382                 static void ConfigSoapExtensionTypes (XmlNode section, ArrayList extensions)
383                 {
384                         if (section.Attributes != null && section.Attributes.Count != 0)
385                                 ThrowException ("Unrecognized attribute", section);
386
387                         XmlNodeList nodes = section.ChildNodes;
388                         foreach (XmlNode child in nodes) {
389                                 XmlNodeType ntype = child.NodeType;
390                                 if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
391                                         continue;
392
393                                 if (ntype != XmlNodeType.Element)
394                                         ThrowException ("Only elements allowed", child);
395                                 
396                                 string name = child.Name;
397                                 if (name == "add") {
398                                         string seType = AttValue ("type", child, false);
399                                         string priority = AttValue ("priority", child);
400                                         string group = AttValue ("group", child);
401                                         if (child.Attributes != null && child.Attributes.Count != 0)
402                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
403
404                                         WSExtensionConfig wse = new WSExtensionConfig ();
405                                         Exception e = wse.SetType (seType);
406                                         if (e != null)
407                                                 ThrowException (e.Message, child);
408
409                                         e = wse.SetPriority (priority);
410                                         if (e != null)
411                                                 ThrowException (e.Message, child);
412
413                                         e = wse.SetGroup (group);
414                                         if (e != null)
415                                                 ThrowException (e.Message, child);
416
417                                         extensions.Add (wse);
418                                         continue;
419                                 }
420
421                                 ThrowException ("Unexpected element", child);
422                         }
423                 }
424                 
425                 static void ConfigFormatExtensionTypes (XmlNode section, WSConfig config)
426                 {
427                         if (section.Attributes != null && section.Attributes.Count != 0)
428                                 ThrowException ("Unrecognized attribute", section);
429
430                         XmlNodeList nodes = section.ChildNodes;
431                         foreach (XmlNode child in nodes) {
432                                 XmlNodeType ntype = child.NodeType;
433                                 if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
434                                         continue;
435
436                                 if (ntype != XmlNodeType.Element)
437                                         ThrowException ("Only elements allowed", child);
438                                 
439                                 string name = child.Name;
440                                 if (name == "add") {
441                                         string typeName = AttValue ("name", child, false);
442                                         if (child.Attributes != null && child.Attributes.Count != 0)
443                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
444
445                                         try {
446                                                 config.FormatExtensionTypes.Add (Type.GetType (typeName, true));
447                                         } catch (Exception e) {
448                                                 ThrowException (e.Message, child);
449                                         }
450                                         continue;
451                                 }
452
453                                 ThrowException ("Unexpected element", child);
454                         }
455                 }
456                 
457                 // To save some typing...
458                 static string AttValue (string name, XmlNode node, bool optional)
459                 {
460                         return HandlersUtil.ExtractAttributeValue (name, node, optional);
461                 }
462
463                 static string AttValue (string name, XmlNode node)
464                 {
465                         return HandlersUtil.ExtractAttributeValue (name, node, true);
466                 }
467
468                 static void ThrowException (string message, XmlNode node)
469                 {
470                         HandlersUtil.ThrowException (message, node);
471                 }
472                 //
473         }
474         
475         class HandlersUtil
476         {
477                 private HandlersUtil ()
478                 {
479                 }
480
481                 static internal string ExtractAttributeValue (string attKey, XmlNode node)
482                 {
483                         return ExtractAttributeValue (attKey, node, false);
484                 }
485                         
486                 static internal string ExtractAttributeValue (string attKey, XmlNode node, bool optional)
487                 {
488                         if (node.Attributes == null) {
489                                 if (optional)
490                                         return null;
491
492                                 ThrowException ("Required attribute not found: " + attKey, node);
493                         }
494
495                         XmlNode att = node.Attributes.RemoveNamedItem (attKey);
496                         if (att == null) {
497                                 if (optional)
498                                         return null;
499                                 ThrowException ("Required attribute not found: " + attKey, node);
500                         }
501
502                         string value = att.Value;
503                         if (value == String.Empty) {
504                                 string opt = optional ? "Optional" : "Required";
505                                 ThrowException (opt + " attribute is empty: " + attKey, node);
506                         }
507
508                         return value;
509                 }
510
511                 static internal void ThrowException (string msg, XmlNode node)
512                 {
513                         if (node != null && node.Name != String.Empty)
514                                 msg = msg + " (node name: " + node.Name + ") ";
515                         throw new ConfigurationException (msg, node);
516                 }
517         }
518
519 }