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