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