Merge branch 'bugfix-main-thread-root'
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Description / BasicProfileChecker.cs
1 // 
2 // System.Web.Services.Description.BasicProfileChecker.cs
3 //
4 // Author:
5 //   Lluis Sanchez (lluis@novell.com)
6 //   Atsushi Enomoto (atsushi@ximian.com)
7 //
8 // Copyright (C) Novell, Inc., 2004
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 #if NET_2_0
33
34 using System.IO;
35 using System.Xml.Schema;
36 using System.Xml.Serialization;
37 using System.Xml;
38 using System.Collections;
39
40 namespace System.Web.Services.Description 
41 {
42         internal class BasicProfileChecker: ConformanceChecker
43         {
44                 public static BasicProfileChecker Instance = new BasicProfileChecker ();
45                 
46                 public override WsiProfiles Claims { 
47                         get { return WsiProfiles.BasicProfile1_1; }
48                 }
49                 
50                 /*
51                 private string GetAbsoluteUri (string baseUri, string relativeUri)
52                 {
53                         string actualBaseUri = baseUri ?? Path.GetFullPath (".") + Path.DirectorySeparatorChar;
54                         Uri uri = new Uri (new Uri (actualBaseUri), relativeUri);
55                         return uri.ToString ();
56                 }
57                 */
58
59                 public override void Check (ConformanceCheckContext ctx, Import value) 
60                 {
61                         if (value.Location == "" || value.Location == null) {
62                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2007);
63                                 return;
64                         }
65                         
66                         if (!new Uri (value.Namespace, UriKind.RelativeOrAbsolute).IsAbsoluteUri)
67                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2803);
68
69                         // LAMESPEC: RetrievalUrl does not seem to help here (in .NET)
70                         //ServiceDescription importer = value.ServiceDescription;
71                         //string absUri = GetAbsoluteUri (importer != null ? importer.RetrievalUrl : null, value.Location);
72                         object doc = ctx.GetDocument (/*absUri*/value.Location, value.Namespace);
73                         if (doc == null) // and looks like .net ignores non-resolvable documentation... I dunno if it makes sense. I don't care :/
74                                 return; //ctx.ReportError (value, "Document '" + value.Location + "' not found");
75                         
76                         if (doc is XmlSchema)
77                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2002);
78                                 
79                         ServiceDescription imported = doc as ServiceDescription;
80                         if (imported == null) {
81                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2001);
82                                 return;
83                         }
84                                 
85                         if (imported.TargetNamespace != value.Namespace)
86                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2005);
87                 }
88                 
89                 public override void Check (ConformanceCheckContext ctx, ServiceDescription value)
90                 {
91                         // R4005 (and R1034, which turned out to be redundant)
92                         if (value.Namespaces != null)
93                                 foreach (XmlQualifiedName qname in value.Namespaces.ToArray ())
94                                         if (qname.Namespace == "http://www.w3.org/XML/1998/namespace")
95                                                 ctx.ReportRuleViolation (value, BasicProfileRules.R4005);
96
97                         CheckDuplicateSoapAddressBinding (ctx, value);
98                 }
99                 
100                 void CheckDuplicateSoapAddressBinding (ConformanceCheckContext ctx, ServiceDescription value)
101                 {
102                         ArrayList locations = new ArrayList ();
103                         foreach (PortType p in value.PortTypes) {
104                                 SoapAddressBinding b = (SoapAddressBinding) p.Extensions.Find (typeof (SoapAddressBinding));
105                                 if (b == null || b.Location == null || b.Location.Length == 0)
106                                         continue;
107                                 if (locations.Contains (b.Location)) {
108                                         ctx.ReportRuleViolation (value, BasicProfileRules.R2711);
109                                         // One report for one ServiceDescription should be enough.
110                                         return;
111                                 }
112                                 locations.Add (b.Location);
113                         }
114                 }
115
116                 public override void Check (ConformanceCheckContext ctx, ServiceDescriptionFormatExtension value)
117                 {
118                         if (value.Required)
119                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2026);
120                 }
121                 
122                 public override void Check (ConformanceCheckContext ctx, MessagePart value)
123                 {
124                         CheckWsdlQName (ctx, value, value.Type);
125                         CheckWsdlQName (ctx, value, value.Element);
126                         
127                         if (value.DefinedByElement && value.Element.Namespace == XmlSchema.Namespace)
128                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2206);
129
130                         if (value.Type != null && value.Type != XmlQualifiedName.Empty &&
131                             value.Element != null && value.Element != XmlQualifiedName.Empty)
132                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2306);
133                 }
134                 
135                 public override void Check (ConformanceCheckContext ctx, Types value)
136                 {
137                 }
138                 
139                 public override void Check (ConformanceCheckContext ctx, Message value)
140                 {
141                 }
142
143                 public override void Check (ConformanceCheckContext ctx, BindingCollection value) {
144                         foreach (Binding b in value)
145                                 foreach (object ext in b.Extensions)
146                                         if (ext.GetType () == typeof (SoapBinding))
147                                                 return;
148
149                         ctx.ReportRuleViolation (value, BasicProfileRules.R2401);
150                 }
151
152                 public override void Check (ConformanceCheckContext ctx, Binding value)
153                 {
154                         SoapBinding sb = (SoapBinding) value.Extensions.Find (typeof(SoapBinding));
155                         if (sb == null)
156                                 return;
157
158                         if (sb.Transport == null || sb.Transport == "") {
159                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2701);
160                                 return;
161                         }
162                         
163                         if (sb.Transport != "http://schemas.xmlsoap.org/soap/http")
164                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2702);
165                         
166                         LiteralType type = GetLiteralBindingType (value);
167                         if (type == LiteralType.NotLiteral)
168                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2706);
169                         else if (type == LiteralType.Inconsistent)
170                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2705);
171                         
172                         // Collect all parts referenced from this type
173                         
174                         Hashtable parts = new Hashtable ();
175                         PortType port = ctx.Services.GetPortType (value.Type);
176                         foreach (Operation op in port.Operations) {
177                                 foreach (OperationMessage om in op.Messages) {
178                                         Message msg = ctx.Services.GetMessage (om.Message);
179                                         foreach (MessagePart part in msg.Parts)
180                                                 parts [part] = part; // do not use Add() - there could be the same MessagePart instance.
181                                 }
182                         }
183                         
184                         foreach (OperationBinding ob in value.Operations) {
185                                 if (ob.Input != null) CheckMessageBinding (ctx, parts, ob.Input);
186                                 if (ob.Output != null) CheckMessageBinding (ctx, parts, ob.Output);
187                                 foreach (FaultBinding fb in ob.Faults)
188                                         CheckMessageBinding (ctx, parts, fb);
189                         }
190                         
191                         if (parts.Count > 0)
192                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2209);
193
194                         // check existence of corresponding operation in portType for each binding operation
195                         if (CheckCorrespondingOperationsForBinding (ctx, value, port))
196                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2718);
197
198                         // check duplicate operation signature.
199                         ArrayList sigs = new ArrayList ();
200                         foreach (OperationBinding ob in value.Operations) {
201                                 if (sigs.Contains (ob.Name))
202                                         ctx.ReportRuleViolation (value, BasicProfileRules.R2710);
203                                 sigs.Add (ob.Name);
204                         }
205
206                         // check namespace declarations.
207                         switch (type) {
208                         case LiteralType.Document:
209                         case LiteralType.Rpc:
210                                 CheckSoapBindingExtensions (ctx, value, type);
211                                 break;
212                         }
213                 }
214                 
215                 bool CheckCorrespondingOperationsForBinding (ConformanceCheckContext ctx, Binding value, PortType port)
216                 {
217                         if (value.Operations.Count != port.Operations.Count)
218                                 return true;
219                         foreach (OperationBinding b in value.Operations) {
220                                 Operation op = port.Operations.Find (b.Name);
221                                 if (op == null)
222                                         return true;
223
224                                 bool msg, bind;
225                                 // input
226                                 msg = op.Messages.Input != null;
227                                 bind = b.Input != null;
228                                 if (msg != bind)
229                                         return true;
230                                 // output
231                                 msg = op.Messages.Output != null;
232                                 bind = b.Output != null;
233                                 if (msg != bind)
234                                         return true;
235                                 // faults
236                                 foreach (FaultBinding fb in b.Faults)
237                                         if (op.Messages.Find (fb.Name) == null)
238                                                 return true;
239                         }
240                         return false;
241                 }
242                 
243                 void CheckSoapBindingExtensions (ConformanceCheckContext ctx, Binding value, LiteralType type)
244                 {
245                         bool violationNS = false;
246                         bool violation2717 = false;
247                         bool violation2720 = false;
248                         bool violation2721 = false;
249
250                         foreach (OperationBinding op in value.Operations) {
251                                 SoapBodyBinding sbb = op.Extensions.Find (typeof (SoapBodyBinding)) as SoapBodyBinding;
252                                 if (sbb != null) {
253                                         if (type == LiteralType.Document && sbb.Namespace != null)
254                                                 violationNS = true;
255                                         if (type == LiteralType.Rpc && sbb.Namespace == null)
256                                                 violation2717 = true;
257                                 }
258
259                                 SoapHeaderBinding shb = op.Extensions.Find (typeof (SoapHeaderBinding)) as SoapHeaderBinding;
260                                 if (shb != null) {
261                                         violationNS |= shb.Namespace != null;
262                                         violation2720 |= !IsValidPart (shb.Part);
263                                 }
264
265                                 SoapHeaderFaultBinding sfhb = op.Extensions.Find (typeof (SoapHeaderFaultBinding)) as SoapHeaderFaultBinding;
266                                 if (sfhb != null) {
267                                         violationNS |= sfhb.Namespace != null;
268                                         violation2720 |= !IsValidPart (sfhb.Part);
269                                 }
270
271                                 SoapFaultBinding sfb = op.Extensions.Find (typeof (SoapFaultBinding)) as SoapFaultBinding;
272                                 if (sfb != null) {
273                                         violation2721 |= sfb.Name == null;
274                                         violationNS |= sfb.Namespace != null;
275                                 }
276                         }
277                         if (violationNS)
278                                 ctx.ReportRuleViolation (value,
279                                         type == LiteralType.Document ?
280                                         BasicProfileRules.R2716 :
281                                         BasicProfileRules.R2726);
282                         if (violation2717)
283                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2717);
284                         if (violation2720)
285                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2720);
286                         if (violation2721)
287                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2721);
288                 }
289                 
290                 bool IsValidPart (string part)
291                 {
292                         if (part == null)
293                                 return false;
294                         try {
295                                 XmlConvert.VerifyNMTOKEN (part);
296                                 return true;
297                         } catch (XmlException) {
298                                 return false;
299                         }
300                 }
301                 
302                 public override void Check (ConformanceCheckContext ctx, OperationBinding value) 
303                 {
304                         bool r2754 = false;
305                         bool r2723 = false;
306                         foreach (FaultBinding fb in value.Faults) {
307                                 SoapFaultBinding sfb = (SoapFaultBinding) value.Extensions.Find (typeof (SoapFaultBinding));
308                                 if (sfb == null)
309                                         continue;
310                                 r2754 |= sfb.Name != fb.Name;
311                                 r2723 |= sfb.Use == SoapBindingUse.Encoded;
312                         }
313                         if (r2754)
314                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2754);
315                         if (r2723)
316                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2723);
317                 }
318                 
319                 void CheckMessageBinding (ConformanceCheckContext ctx, Hashtable portParts, MessageBinding value)
320                 {
321                         SoapBodyBinding sbb = (SoapBodyBinding) value.Extensions.Find (typeof(SoapBodyBinding));
322                         Message msg = FindMessage (ctx, value);
323                         LiteralType bt = GetLiteralBindingType (value.OperationBinding.Binding);
324                         
325                         if (sbb != null) 
326                         {
327                                 if (bt == LiteralType.Document)
328                                 {
329                                         if (sbb.Parts != null && sbb.Parts.Length > 1)
330                                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2201);
331
332                                         if (sbb.Parts == null) {
333                                                 if (msg.Parts != null && msg.Parts.Count > 1)
334                                                         ctx.ReportRuleViolation (value, BasicProfileRules.R2210);
335                                                 if (msg.Parts.Count == 1)
336                                                         portParts.Remove (msg.Parts[0]);
337                                         }
338                                         else {
339                                                 if (sbb.Parts.Length == 0 && msg.Parts.Count == 1) {
340                                                         portParts.Remove (msg.Parts[0]);
341                                                 } else {
342                                                         foreach (string part in sbb.Parts) {
343                                                                 MessagePart mp = msg.FindPartByName (part);
344                                                                 portParts.Remove (mp);
345                                                                 if (!mp.DefinedByElement)
346                                                                         ctx.ReportRuleViolation (value, BasicProfileRules.R2204);
347                                                         }
348                                                 }
349                                         }
350                                 }
351                                 else if (bt == LiteralType.Rpc) 
352                                 {
353                                         if (sbb.Parts != null) {
354                                                 foreach (string part in sbb.Parts) {
355                                                         MessagePart mp = msg.FindPartByName (part);
356                                                         portParts.Remove (mp);
357                                                         if (!mp.DefinedByType)
358                                                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2203);
359                                                 }
360                                         }
361                                 }
362                         }
363                         
364                         SoapHeaderBinding shb = (SoapHeaderBinding) value.Extensions.Find (typeof(SoapHeaderBinding));
365                         if (shb != null) {
366                                 Message hm = ctx.Services.GetMessage (shb.Message);
367                                 MessagePart mp = hm.FindPartByName (shb.Part);
368                                 portParts.Remove (mp);
369                                 if (mp != null && !mp.DefinedByElement)
370                                         ctx.ReportRuleViolation (value, BasicProfileRules.R2205);
371                         }
372                         
373                         SoapHeaderFaultBinding shfb = (SoapHeaderFaultBinding) value.Extensions.Find (typeof(SoapHeaderFaultBinding));
374                         if (shfb != null) {
375                                 Message hm = ctx.Services.GetMessage (shfb.Message);
376                                 MessagePart mp = hm.FindPartByName (shfb.Part);
377                                 portParts.Remove (mp);
378                                 if (mp != null && !mp.DefinedByElement)
379                                         ctx.ReportRuleViolation (value, BasicProfileRules.R2205);
380                         }
381                         
382                         // TODO: SoapFaultBinding ??
383                 }
384                 
385                 Message FindMessage (ConformanceCheckContext ctx, MessageBinding mb)
386                 {
387                         PortType pt = ctx.Services.GetPortType (mb.OperationBinding.Binding.Type);
388                         foreach (Operation op in pt.Operations)
389                                 if (op.IsBoundBy (mb.OperationBinding)) {
390                                         OperationMessage om;
391                                         if (mb is InputBinding) om = op.Messages.Input;
392                                         else if (mb is OutputBinding) om = op.Messages.Output;
393                                         else if (mb is FaultBinding) om = op.Faults [mb.Name];
394                                         else return null;
395                                         if (om != null)
396                                                 return ctx.Services.GetMessage (om.Message);
397                                         else
398                                                 return null;
399                                 }
400                         return null;
401                 }
402                 
403                 public override void Check (ConformanceCheckContext ctx, Operation value)
404                 {
405                         switch (value.Messages.Flow) {
406                         case OperationFlow.SolicitResponse:
407                         case OperationFlow.Notification:
408                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2303);
409                                 break;
410                         }
411
412                         CheckR2305 (ctx, value);
413                 }
414
415                 void CheckR2305 (ConformanceCheckContext ctx, Operation value)
416                 {
417                         string [] order = value.ParameterOrder;
418                         ServiceDescription sd = value.PortType.ServiceDescription;
419                         Message omitted = null;
420                         foreach (OperationMessage m in value.Messages) {
421                                 if (m.Name == null)
422                                         continue; // it is doubtful, but R2305 is not to check such cases anyways.
423                                 Message msg = sd.Messages [m.Name];
424                                 if (msg == null)
425                                         continue; // it is doubtful, but R2305 is not to check such cases anyways.
426                                 foreach (MessagePart p in msg.Parts) {
427                                         if (order != null && Array.IndexOf (order, p.Name) >= 0)
428                                                 continue;
429                                         if (omitted == null) {
430                                                 omitted = msg;
431                                                 continue;
432                                         }
433                                         ctx.ReportRuleViolation (value, BasicProfileRules.R2305);
434                                         return;
435                                 }
436                         }
437                 }
438
439                 public override void Check (ConformanceCheckContext ctx, OperationMessage value) { }
440                 public override void Check (ConformanceCheckContext ctx, Port value) { }
441
442                 public override void Check (ConformanceCheckContext ctx, PortType value)
443                 {
444                         ArrayList names = new ArrayList ();
445                         foreach (Operation o in value.Operations) {
446                                 if (names.Contains (o.Name))
447                                         ctx.ReportRuleViolation (value, BasicProfileRules.R2304);
448                                 else
449                                         names.Add (o.Name);
450                         }
451                 }
452
453                 public override void Check (ConformanceCheckContext ctx, Service value) { }
454                 
455                 public override void Check (ConformanceCheckContext ctx, XmlSchema s)
456                 {
457                         if (s.TargetNamespace == null || s.TargetNamespace == "") {
458                                 foreach (XmlSchemaObject ob in s.Items)
459                                         if (!(ob is XmlSchemaImport) && !(ob is XmlSchemaAnnotation)) {
460                                                 ctx.ReportRuleViolation (s, BasicProfileRules.R2105);
461                                                 break;
462                                         }
463                         }
464                 }
465                 
466                 public override void Check (ConformanceCheckContext ctx, XmlSchemaImport value)
467                 {
468                         // LAMESPEC: same here to Check() for Import.
469                         XmlSchema doc = ctx.GetDocument (value.SchemaLocation, value.Namespace) as XmlSchema;
470                         if (doc == null) ctx.ReportError (value, "Schema '" + value.SchemaLocation + "' not found");
471                 }
472                 
473                 public override void Check (ConformanceCheckContext ctx, XmlSchemaAttribute value)
474                 {
475                         CheckSchemaQName (ctx, value, value.RefName);
476                         CheckSchemaQName (ctx, value, value.SchemaTypeName);
477                         
478                         XmlAttribute[] uatts = value.UnhandledAttributes;
479                         if (uatts != null) {
480                                 foreach (XmlAttribute at in uatts)
481                                         if (at.LocalName == "arrayType" && at.NamespaceURI == "http://schemas.xmlsoap.org/wsdl/")
482                                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2111);
483                         }
484                 }
485                 
486                 public override void Check (ConformanceCheckContext ctx, XmlSchemaAttributeGroupRef value)
487                 {
488                         CheckSchemaQName (ctx, value, value.RefName);
489                 }
490                 
491                 public override void Check (ConformanceCheckContext ctx, XmlSchemaComplexContentExtension value)
492                 {
493                         CheckSchemaQName (ctx, value, value.BaseTypeName);
494                         if (value.BaseTypeName.Namespace == "http://schemas.xmlsoap.org/soap/encoding/" && value.BaseTypeName.Name == "Array")
495                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2110);
496                 }
497                 
498                 public override void Check (ConformanceCheckContext ctx, XmlSchemaComplexContentRestriction value)
499                 {
500                         CheckSchemaQName (ctx, value, value.BaseTypeName);
501                         if (value.BaseTypeName.Namespace == "http://schemas.xmlsoap.org/soap/encoding/" && value.BaseTypeName.Name == "Array")
502                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2110);
503                 }
504                 
505                 public override void Check (ConformanceCheckContext ctx, XmlSchemaElement value)
506                 {
507                         CheckSchemaQName (ctx, value, value.RefName);
508                         CheckSchemaQName (ctx, value, value.SubstitutionGroup);
509                         CheckSchemaQName (ctx, value, value.SchemaTypeName);
510                         if (value.Name != null && value.Name.StartsWith ("ArrayOf", StringComparison.Ordinal))
511                                 ctx.ReportRuleViolation (value, BasicProfileRules.R2112);
512                 }
513                 
514                 public override void Check (ConformanceCheckContext ctx, XmlSchemaGroupRef value)
515                 {
516                         CheckSchemaQName (ctx, value, value.RefName);
517                 }
518                 
519                 public override void Check (ConformanceCheckContext ctx, XmlSchemaKeyref value)
520                 {
521                         CheckSchemaQName (ctx, value, value.Refer);
522                 }
523                 
524                 public override void Check (ConformanceCheckContext ctx, XmlSchemaSimpleContentExtension value)
525                 {
526                         CheckSchemaQName (ctx, value, value.BaseTypeName);
527                 }
528                 
529                 public override void Check (ConformanceCheckContext ctx, XmlSchemaSimpleContentRestriction value)
530                 {
531                         CheckSchemaQName (ctx, value, value.BaseTypeName);
532                 }
533                 
534                 public override void Check (ConformanceCheckContext ctx, XmlSchemaSimpleTypeList value)
535                 {
536                         CheckSchemaQName (ctx, value, value.ItemTypeName);
537                 }
538                 
539                 public override void Check (ConformanceCheckContext ctx, XmlSchemaSimpleTypeRestriction value)
540                 {
541                         CheckSchemaQName (ctx, value, value.BaseTypeName);
542                 }
543                 
544                 public override void Check (ConformanceCheckContext ctx, XmlSchemaSimpleTypeUnion value)
545                 {
546                         if (value.MemberTypes != null) {
547                                 foreach (XmlQualifiedName name in value.MemberTypes)
548                                         CheckSchemaQName (ctx, value, name);
549                         }
550                 }
551                 
552                 // Helper methods
553                 
554                 void CheckWsdlQName (ConformanceCheckContext ctx, object element, XmlQualifiedName name)
555                 {
556                         if (name == null || name == XmlQualifiedName.Empty) return;
557                         if (name.Namespace == "" || name.Namespace == XmlSchema.Namespace) return;
558                         
559                         if (ctx.ServiceDescription.Types != null && ctx.ServiceDescription.Types.Schemas != null) 
560                         {
561                                 foreach (XmlSchema s in ctx.ServiceDescription.Types.Schemas)
562                                 {
563                                         if (s.TargetNamespace == name.Namespace) return;
564                                         foreach (XmlSchemaObject i in s.Includes)
565                                                 if ((i is XmlSchemaImport) && ((XmlSchemaImport)i).Namespace == name.Namespace) return;
566                                 }
567                         }
568                         ctx.ReportRuleViolation (element, BasicProfileRules.R2101);
569                 }
570                 
571                 void CheckSchemaQName (ConformanceCheckContext ctx, object element, XmlQualifiedName name)
572                 {
573                         if (name == null || name == XmlQualifiedName.Empty) return;
574                         if (name.Namespace == "" || name.Namespace == XmlSchema.Namespace) return;
575                         if (ctx.CurrentSchema.TargetNamespace == name.Namespace) return;
576                         
577                         foreach (XmlSchemaObject i in ctx.CurrentSchema.Includes)
578                                 if ((i is XmlSchemaImport) && ((XmlSchemaImport)i).Namespace == name.Namespace) return;
579                                 
580                         ctx.ReportRuleViolation (element, BasicProfileRules.R2102);
581                 }
582                 
583                 LiteralType GetLiteralBindingType (Binding b)
584                 {
585                         SoapBinding sb = (SoapBinding) b.Extensions.Find (typeof(SoapBinding));
586                         SoapBindingStyle style = (sb != null) ? sb.Style : SoapBindingStyle.Document;
587                         if (style == SoapBindingStyle.Default) style = SoapBindingStyle.Document;
588                         
589                         foreach (OperationBinding ob in b.Operations) {
590                                 SoapOperationBinding sob = (SoapOperationBinding) ob.Extensions.Find (typeof(SoapOperationBinding));
591                                 if (sob.Style != SoapBindingStyle.Default && sob.Style != style)
592                                         return LiteralType.Inconsistent;
593                                 if (ob.Input != null) {
594                                         SoapBodyBinding sbb = (SoapBodyBinding) ob.Input.Extensions.Find (typeof(SoapBodyBinding));
595                                         if (sbb != null && sbb.Use != SoapBindingUse.Literal) return LiteralType.NotLiteral;
596                                         SoapFaultBinding sfb = (SoapFaultBinding) ob.Input.Extensions.Find (typeof(SoapFaultBinding));
597                                         if (sfb != null && sfb.Use != SoapBindingUse.Literal) return LiteralType.NotLiteral;
598                                         SoapHeaderBinding shb = (SoapHeaderBinding) ob.Input.Extensions.Find (typeof(SoapHeaderBinding));
599                                         if (shb != null && shb.Use != SoapBindingUse.Literal) return LiteralType.NotLiteral;
600                                         SoapHeaderFaultBinding shfb = (SoapHeaderFaultBinding) ob.Input.Extensions.Find (typeof(SoapHeaderFaultBinding));
601                                         if (shfb != null && shfb.Use != SoapBindingUse.Literal) return LiteralType.NotLiteral;
602                                 }
603                                 if (ob.Output != null) {
604                                         SoapBodyBinding sbb = (SoapBodyBinding) ob.Output.Extensions.Find (typeof(SoapBodyBinding));
605                                         if (sbb != null && sbb.Use != SoapBindingUse.Literal) return LiteralType.NotLiteral;
606                                         SoapFaultBinding sfb = (SoapFaultBinding) ob.Input.Extensions.Find (typeof(SoapFaultBinding));
607                                         if (sfb != null && sfb.Use != SoapBindingUse.Literal) return LiteralType.NotLiteral;
608                                         SoapHeaderBinding shb = (SoapHeaderBinding) ob.Input.Extensions.Find (typeof(SoapHeaderBinding));
609                                         if (shb != null && shb.Use != SoapBindingUse.Literal) return LiteralType.NotLiteral;
610                                         SoapHeaderFaultBinding shfb = (SoapHeaderFaultBinding) ob.Input.Extensions.Find (typeof(SoapHeaderFaultBinding));
611                                         if (shfb != null && shfb.Use != SoapBindingUse.Literal) return LiteralType.NotLiteral;
612                                 }
613                         }
614                         if (style == SoapBindingStyle.Document) return LiteralType.Document;
615                         else return LiteralType.Rpc;
616                 }
617                 
618                 enum LiteralType {
619                         NotLiteral,
620                         Inconsistent,
621                         Rpc,
622                         Document
623                 }
624         }
625         
626         internal class BasicProfileRules
627         {
628                 #region "Basic Profile 1.1 Section 4 (Service Description)"
629
630                 // (BTW R1034 turned out to be a spec bug.)
631
632         // 4.1 Required Description
633                 // Can't check: R0001
634
635         // 4.2 Document Structure
636
637                 // R2028, R2029: schema conformance, depends on underlying XML
638
639                 public static readonly ConformanceRule R2001 = new ConformanceRule (
640                         "R2001", 
641                         "A DESCRIPTION MUST only use the WSDL \"import\" statement to import another WSDL description",
642                         "");
643
644                 public static readonly ConformanceRule R2803 = new ConformanceRule (
645                         "R2803", 
646                         "In a DESCRIPTION, the namespace attribute of the wsdl:import MUST NOT be a relative URI.",
647                         "");
648
649                 public static readonly ConformanceRule R2002 = new ConformanceRule (
650                         "R2002", 
651                         "To import XML Schema Definitions, a DESCRIPTION MUST use the XML Schema \"import\" statement",
652                         "");
653
654                 // R2003: depends on ServiceDescription raw XML.
655                 // R2004, R2009, R2010, R2011: requires schema resolution
656                 // which depends on XmlResolver, while 1) XmlUrlResolver
657                 // might not always be proper (e.g. network resolution) and
658                 // 2) custom XmlResolver might resolve non-XML.
659
660                 public static readonly ConformanceRule R2007 = new ConformanceRule (
661                         "R2007", 
662                         "A DESCRIPTION MUST specify a non-empty location attribute on the wsdl:import element",
663                         "");
664
665                 // R2008: denotes a possibility that cannot be verified.
666
667                 // R2022, R2023, R4004: depends on underlying XML, which 
668                 // is impossible when ServiceDescription is already read
669                 // (WebServiceInteroperability.CheckConformance() is the case).
670
671                 public static readonly ConformanceRule R4005 = new ConformanceRule (
672                         "R4005",
673                         "A DESCRIPTION SHOULD NOT contain the namespace declaration xmlns:xml=\"http://www.w3.org/XML/1998/namespace\"",
674                         "");
675
676                 // R4002, R4003: depends on underlying XML
677
678                 public static readonly ConformanceRule R2005 = new ConformanceRule (
679                         "R2005", 
680                         "The targetNamespace attribute on the wsdl:definitions element of a description that is being imported MUST have same the value as the namespace attribute on the wsdl:import element in the importing DESCRIPTION",
681                         "");
682
683                 // R2030: is satisfied by API nature (DocumentableItem).
684
685                 // R2025: cannot be checked.
686
687                 public static readonly ConformanceRule R2026 = new ConformanceRule (
688                         "R2026", 
689                         "A DESCRIPTION SHOULD NOT include extension elements with a wsdl:required attribute value of \"true\" on any WSDL construct (wsdl:binding,  wsdl:portType, wsdl:message, wsdl:types or wsdl:import) that claims conformance to the Profile",
690                         "");
691
692                 // R2027: is about the CONSUMER, cannot be checked.
693
694         // 4.3 Types
695
696                 public static readonly ConformanceRule R2101 = new ConformanceRule (
697                         "R2101", 
698                         "A DESCRIPTION MUST NOT use QName references to elements in namespaces that have been neither imported, nor defined in the referring WSDL document",
699                         "");
700                         
701                 public static readonly ConformanceRule R2102 = new ConformanceRule (
702                         "R2102", 
703                         "A QName reference to a Schema component in a DESCRIPTION MUST use the namespace defined in the targetNamespace attribute on the xsd:schema element, or to a namespace defined in the namespace attribute on an xsd:import element within the xsd:schema element",
704                         "");
705                         
706                 public static readonly ConformanceRule R2105 = new ConformanceRule (
707                         "R2105", 
708                         "All xsd:schema elements contained in a wsdl:types element of a DESCRIPTION MUST have a targetNamespace attribute with a valid and non-null value, UNLESS the xsd:schema element has xsd:import and/or xsd:annotation as its only child element(s)",
709                         "");
710                         
711                 public static readonly ConformanceRule R2110 = new ConformanceRule (
712                         "R2110", 
713                         "In a DESCRIPTION, array declarations MUST NOT extend or restrict the soapenc:Array type",
714                         "");
715                         
716                 public static readonly ConformanceRule R2111 = new ConformanceRule (
717                         "R2111", 
718                         "In a DESCRIPTION, array declarations MUST NOT use wsdl:arrayType attribute in the type declaration",
719                         "");
720                         
721                 public static readonly ConformanceRule R2112 = new ConformanceRule (
722                         "R2112", 
723                         "In a DESCRIPTION, elements SHOULD NOT be named using the convention ArrayOfXXX.",
724                         "");
725
726                 // R2113: is about ENVELOPE.
727
728                 // R2114: is satisfied by our processor.
729
730         // 4.4 Messages
731         
732                 public static readonly ConformanceRule R2201 = new ConformanceRule (
733                         "R2201", 
734                         "A document-literal binding in a DESCRIPTION MUST, in each of its soapbind:body element(s), have at most one part listed in the parts attribute, if the parts attribute is specified",
735                         "");
736
737                 public static readonly ConformanceRule R2209 = new ConformanceRule (
738                         "R2209", 
739                         "A wsdl:binding in a DESCRIPTION SHOULD bind every wsdl:part of a wsdl:message in the wsdl:portType to which it refers to one of soapbind:body, soapbind:header, soapbind:fault  or soapbind:headerfault",
740                         "");
741                 
742                 public static readonly ConformanceRule R2210 = new ConformanceRule (
743                         "R2210", 
744                         "If a document-literal binding in a DESCRIPTION does not specify the parts attribute on a soapbind:body element, the corresponding abstract wsdl:message MUST define zero or one wsdl:parts",
745                         "");
746
747                 // R2202: Suggestion.
748
749                 public static readonly ConformanceRule R2203 = new ConformanceRule (
750                         "R2203", 
751                         "An rpc-literal binding in a DESCRIPTION MUST refer, in its soapbind:body element(s), only to wsdl:part element(s) that have been defined using the type attribute",
752                         "");
753
754                 // R2211: Related to ENVELOPE
755                 // R2207: is about allowed condition (MAY).
756
757                 public static readonly ConformanceRule R2204 = new ConformanceRule (
758                         "R2204", 
759                         "A document-literal binding in a DESCRIPTION MUST refer, in each of its soapbind:body element(s), only to wsdl:part element(s) that have been defined using the element attribute",
760                         "");
761
762                 // R2208: is about allowed condition (MAY).
763                 // R2212, R2213, R2214: related to ENVELOPE
764
765                 public static readonly ConformanceRule R2205 = new ConformanceRule (
766                         "R2205", 
767                         "A wsdl:binding in a DESCRIPTION MUST refer, in each of its soapbind:header, soapbind:headerfault and soapbind:fault elements, only to wsdl:part element(s) that have been defined using the element attribute",
768                         "");
769
770                 public static readonly ConformanceRule R2206 = new ConformanceRule (
771                         "R2206", 
772                         "A wsdl:message in a DESCRIPTION containing a wsdl:part that uses the element attribute MUST refer, in that attribute, to a global element declaration",
773                         "");
774
775         // 4.5 Port Types
776
777                 // R2301: Related to ENVELOPE.
778                 // R2302: Optional
779
780                 // btw it's not on Basic Profile TAD
781                 public static readonly ConformanceRule R2303 = new ConformanceRule (
782                         "R2303", 
783                         "A DESCRIPTION MUST NOT use Solicit-Response and Notification type operations in a wsdl:portType definition.",
784                         "");
785
786                 public static readonly ConformanceRule R2304 = new ConformanceRule (
787                         "R2304", 
788                         "A wsdl:portType in a DESCRIPTION MUST have operations with distinct values for their name attributes.",
789                         "");
790
791                 public static readonly ConformanceRule R2305 = new ConformanceRule (
792                         "R2305", 
793                         "A wsdl:operation element child of a wsdl:portType element in a DESCRIPTION MUST be constructed so that the parameterOrder attribute, if present, omits at most 1 wsdl:part from the output message.",
794                         "");
795
796                 public static readonly ConformanceRule R2306 = new ConformanceRule (
797                         "R2306", 
798                         "A wsdl:message in a DESCRIPTION MUST NOT specify both type and element attributes on the same wsdl:part.",
799                         "");
800
801         // 4.6 Bindings
802
803                 public static readonly ConformanceRule R2401 = new ConformanceRule (
804                         "R2401", 
805                         "A wsdl:binding element in a DESCRIPTION MUST use WSDL SOAP Binding as defined in WSDL 1.1 Section 3.",
806                         "");
807
808         // 4.7 SOAP Binding
809                 
810                 public static readonly ConformanceRule R2701 = new ConformanceRule (
811                         "R2701", 
812                         "The wsdl:binding element in a DESCRIPTION MUST be constructed so that its soapbind:binding child element specifies the transport attribute",
813                         "");
814                         
815                 public static readonly ConformanceRule R2702 = new ConformanceRule (
816                         "R2702", 
817                         "A wsdl:binding element in a DESCRIPTION MUST specify the HTTP transport protocol with SOAP binding. Specifically, the transport attribute of its soapbind:binding child MUST have the value \"http://schemas.xmlsoap.org/soap/http\"",
818                         "");
819                         
820                 public static readonly ConformanceRule R2705 = new ConformanceRule (
821                         "R2705", 
822                         "A wsdl:binding in a DESCRIPTION MUST use either be a rpc-literal binding or a document-literal binding",
823                         "");
824                         
825                 public static readonly ConformanceRule R2706 = new ConformanceRule (
826                         "R2706", 
827                         "A wsdl:binding in a DESCRIPTION MUST use the value of \"literal\" for the use attribute in all soapbind:body, soapbind:fault, soapbind:header and soapbind:headerfault elements",
828                         "");
829                         
830                 // R2709: Suggestion.
831
832                 public static readonly ConformanceRule R2710 = new ConformanceRule (
833                         "R2710", 
834                         "The operations in a wsdl:binding in a DESCRIPTION MUST result in operation signatures that are different from one another.",
835                         "");
836                         
837                 public static readonly ConformanceRule R2711 = new ConformanceRule (
838                         "R2711", 
839                         "A DESCRIPTION SHOULD NOT have more than one wsdl:port with the same value for the location attribute of the soapbind:address element.",
840                         "");
841                         
842                 // R2712: related to ENVELOPE.
843                 // R2714: related to INSTANCE.
844                 // R2750, R2727: related to CONSUMER.
845
846                 public static readonly ConformanceRule R2716 = new ConformanceRule (
847                         "R2716", 
848                         "A document-literal binding in a DESCRIPTION MUST NOT have the namespace attribute specified on contained soapbind:body, soapbind:header, soapbind:headerfault and soapbind:fault elements.",
849                         "");
850                         
851                 public static readonly ConformanceRule R2717 = new ConformanceRule (
852                         "R2717", 
853                         "An rpc-literal binding in a DESCRIPTION MUST have the namespace attribute specified, the value of which MUST be an absolute URI, on contained  soapbind:body elements.",
854                         "");
855                         
856                 public static readonly ConformanceRule R2726 = new ConformanceRule (
857                         "R2726", 
858                         "An rpc-literal binding in a DESCRIPTION MUST NOT have the namespace attribute specified on contained soapbind:header,  soapbind:headerfault and soapbind:fault elements.",
859                         "");
860                         
861
862                 public static readonly ConformanceRule R2718 = new ConformanceRule (
863                         "R2718", 
864                         "A wsdl:binding in a DESCRIPTION MUST have the same set of wsdl:operations as the wsdl:portType to which it refers.",
865                         "");
866                         
867
868                 // R2719: is about allowed condition (MAY).
869                 // R2740, R2741: no way to detect known faults here.
870                 // R2742, R2743: related to ENVELOPE.
871
872                 public static readonly ConformanceRule R2720 = new ConformanceRule (
873                         "R2720", 
874                         "A wsdl:binding in a DESCRIPTION MUST use the part attribute with a schema type of \"NMTOKEN\" on all contained soapbind:header and soapbind:headerfault elements.",
875                         "");
876                         
877
878                 // R2749: is satisfied by API nature.
879
880                 public static readonly ConformanceRule R2721 = new ConformanceRule (
881                         "R2721", 
882                         "A wsdl:binding in a DESCRIPTION MUST have the name  attribute specified on all contained soapbind:fault elements.",
883                         "");
884
885                 public static readonly ConformanceRule R2754 = new ConformanceRule (
886                         "R2754", 
887                         "In a DESCRIPTION, the value of the name attribute on a soapbind:fault element MUST match the value of the name attribute on its parent wsdl:fault element.",
888                         "");
889
890                 // R2722: is about allowed condition (MAY).
891
892                 public static readonly ConformanceRule R2723 = new ConformanceRule (
893                         "R2723", 
894                         "f in a wsdl:binding in a DESCRIPTION the use attribute on a contained soapbind:fault element is present, its value MUST be \"literal\".",
895                         "");
896
897                 // R2707: is satisfied by our implementation.
898                 // R2724, R2725: related to INSTANCE.
899                 // R2729, R2735: related to ENVELOPE.
900                 // R2755: related to MESSAGE.
901                 // R2737, R2738, R2739, R2753: related to ENVELOPE.
902                 // R2751, R2752: related to ENVELOPE.
903                 // R2744, R2745: related to MESSAGE.
904                 // R2747, R2748: related to CONSUMER.
905
906         // 4.8 Use of XML Schema
907
908                 // R2800: satisfied by API nature.
909                 // R2801: ditto.
910
911                 #endregion
912
913                 /*
914
915                 Below are the combination of these documents:
916                 http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html
917                 http://www.ws-i.org/Testing/Tools/2005/01/BP11_TAD_1-1.htm
918
919                 TAD No. component       recomm. WS-I Req.
920                 BP2010  portType                R2304   
921                 BP2011  types                   R2011   
922                 BP2012  binding                 R2204   
923                 BP2013  binding                 R2203   
924                 BP2014  operation               R2305   
925                 BP2017  binding                 R2705,R2706
926                 BP2018  definitions             R2023,R2030
927                 BP2019  binding                 R2716   
928                 BP2020  binding                 R2717   
929                 BP2021  binding                 R2720,R2749
930                 BP2022  binding                 R2721   
931                 BP2032  binding                 R2754   
932                 BP2034  definitions     rec.    R1034,R4005
933                 BP2098  import                  R2007   
934                 BP2101  definitions             R2001   
935                 BP2103  definitions             R2003   
936                 BP2104  definitions             R2005   
937                 BP2105  definitions             R2022,R2030
938                 BP2107  types                   R2105   
939                 BP2108  types                   R2110,R2111
940                 BP2110  types           rec.    R2112   
941                 BP2111  binding                 R2201   
942                 BP2112  binding                 R2207   
943                 BP2113  binding                 R2205   
944                 BP2114  binding         rec.    R2209   
945                 BP2115  message                 R2206   
946                 BP2116  message                 R2306   
947                 BP2117  binding                 R2726   
948                 BP2118  binding                 R2718   
949                 BP2119  binding                 R2210   
950                 BP2120  binding                 R2710   
951                 BP2122  types                   R2801   
952                 BP2123  definitions     rec.    R2026   
953                 BP2803  import                  R2803   
954
955                 */
956         }
957 }
958
959 #endif