2 // HttpTransportBindingElementTest.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005 Novell, Inc. http://www.novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Collections.ObjectModel;
32 using System.Net.Security;
33 using System.Reflection;
34 using System.ServiceModel;
35 using System.ServiceModel.Channels;
36 using System.ServiceModel.Description;
37 using System.Threading;
39 using NUnit.Framework;
41 using MonoTests.Helpers;
42 using System.Security.Authentication.ExtendedProtection;
44 namespace MonoTests.System.ServiceModel.Channels
47 public class HttpTransportBindingElementTest
49 static BindingParameterCollection empty_params =
50 new BindingParameterCollection ();
53 public void DefaultValues ()
55 HttpTransportBindingElement be =
56 new HttpTransportBindingElement ();
57 Assert.AreEqual (false, be.AllowCookies, "#1");
58 Assert.AreEqual (AuthenticationSchemes.Anonymous,
59 be.AuthenticationScheme, "#2");
60 Assert.AreEqual (false, be.BypassProxyOnLocal, "#3");
61 Assert.AreEqual (default (HostNameComparisonMode),
62 be.HostNameComparisonMode, "#4");
63 Assert.AreEqual (0x10000, be.MaxBufferSize, "#6");
64 Assert.IsNull (be.ProxyAddress, "#7");
65 Assert.AreEqual (AuthenticationSchemes.Anonymous,
66 be.ProxyAuthenticationScheme, "#8");
67 Assert.AreEqual (String.Empty, be.Realm, "#9");
68 Assert.AreEqual ("http", be.Scheme, "#10");
69 Assert.AreEqual (default (TransferMode),
70 be.TransferMode, "#11");
71 Assert.AreEqual (false,
72 be.UnsafeConnectionNtlmAuthentication, "#12");
73 Assert.AreEqual (true, be.UseDefaultWebProxy, "#13");
77 public void CanBuildChannelFactory ()
79 HttpTransportBindingElement be =
80 new HttpTransportBindingElement ();
81 BindingContext ctx = new BindingContext (
82 new CustomBinding (), empty_params);
83 Assert.IsTrue (be.CanBuildChannelFactory<IRequestChannel> (ctx), "#1");
84 Assert.IsFalse (be.CanBuildChannelFactory<IInputChannel> (ctx), "#2");
85 Assert.IsFalse (be.CanBuildChannelFactory<IReplyChannel> (ctx), "#3");
86 Assert.IsFalse (be.CanBuildChannelFactory<IOutputChannel> (ctx), "#4");
87 // seems like it does not support session channels by itself ?
88 Assert.IsFalse (be.CanBuildChannelFactory<IRequestSessionChannel> (ctx), "#5");
89 Assert.IsFalse (be.CanBuildChannelFactory<IInputSessionChannel> (ctx), "#6");
90 Assert.IsFalse (be.CanBuildChannelFactory<IReplySessionChannel> (ctx), "#7");
91 Assert.IsFalse (be.CanBuildChannelFactory<IOutputSessionChannel> (ctx), "#8");
93 // IServiceChannel is not supported
94 Assert.IsFalse (be.CanBuildChannelListener<IServiceChannel> (ctx), "#9");
98 public void CanBuildChannelListener ()
100 HttpTransportBindingElement be =
101 new HttpTransportBindingElement ();
102 BindingContext ctx = new BindingContext (
103 new CustomBinding (), empty_params);
104 Assert.IsTrue (be.CanBuildChannelListener<IReplyChannel> (ctx), "#1");
105 Assert.IsFalse (be.CanBuildChannelListener<IOutputChannel> (ctx), "#2");
106 Assert.IsFalse (be.CanBuildChannelListener<IRequestChannel> (ctx), "#3");
107 Assert.IsFalse (be.CanBuildChannelListener<IInputChannel> (ctx), "#4");
108 // seems like it does not support session channels by itself ?
109 Assert.IsFalse (be.CanBuildChannelListener<IReplySessionChannel> (ctx), "#5");
110 Assert.IsFalse (be.CanBuildChannelListener<IOutputSessionChannel> (ctx), "#6");
111 Assert.IsFalse (be.CanBuildChannelListener<IRequestSessionChannel> (ctx), "#7");
112 Assert.IsFalse (be.CanBuildChannelListener<IInputSessionChannel> (ctx), "#8");
114 // IServiceChannel is not supported
115 Assert.IsFalse (be.CanBuildChannelListener<IServiceChannel> (ctx), "#9");
119 public void BuildChannelFactory ()
121 BindingContext ctx = new BindingContext (
123 new HttpTransportBindingElement ()),
125 // returns HttpChannelFactory
126 IChannelFactory<IRequestChannel> f =
127 ctx.BuildInnerChannelFactory<IRequestChannel> ();
128 f.Open (); // required
129 IChannel c = f.CreateChannel (new EndpointAddress (
130 "http://www.mono-project.com"));
134 [ExpectedException (typeof (InvalidOperationException))]
135 public void CreateChannelWithoutOpen ()
137 BindingContext ctx = new BindingContext (
139 new HttpTransportBindingElement ()),
141 // returns HttpChannelFactory
142 IChannelFactory<IRequestChannel> f =
143 ctx.BuildInnerChannelFactory<IRequestChannel> ();
144 IChannel c = f.CreateChannel (new EndpointAddress (
145 "http://www.mono-project.com"));
149 public void BuildChannelFactoryTwoHttp ()
151 BindingContext ctx = new BindingContext (
153 new HttpTransportBindingElement (),
154 new HttpTransportBindingElement ()),
156 ctx.BuildInnerChannelFactory<IRequestChannel> ();
160 public void BuildChannelFactoryHttpThenMessage ()
162 BindingContext ctx = new BindingContext (
164 new HttpTransportBindingElement (),
165 new BinaryMessageEncodingBindingElement ()),
167 IChannelFactory<IRequestChannel> cf =
168 ctx.BuildInnerChannelFactory<IRequestChannel> ();
173 // with July CTP it still works ...
174 public void BuildChannelFactoryHttpNoMessage ()
176 BindingContext ctx = new BindingContext (
178 new HttpTransportBindingElement ()),
180 IChannelFactory<IRequestChannel> cf =
181 ctx.BuildInnerChannelFactory<IRequestChannel> ();
186 public void BuildChannelFactoryIgnoresRemaining ()
188 BindingContext ctx = new BindingContext (
190 new HttpTransportBindingElement (),
191 new InvalidBindingElement ()),
193 ctx.BuildInnerChannelFactory<IRequestChannel> ();
196 // Disable this test anytime when HttpTransportBindingElement.BuildChannelFactory() doesn't return ChannelFactoryBase`1 anymore. It's not an API requirement.
198 [ExpectedException (typeof (ArgumentNullException))]
199 public void BuildChannelFactory_CreateChannelNullVia ()
201 var ctx = new BindingContext (new CustomBinding (), empty_params);
202 var cf = new HttpTransportBindingElement ().BuildChannelFactory<IRequestChannel> (ctx);
203 Assert.IsTrue (cf is ChannelFactoryBase<IRequestChannel>, "#1");
205 cf.CreateChannel (new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort ()), null);
209 [ExpectedException (typeof (ArgumentException))]
210 public void CreateChannelInvalidScheme ()
212 IChannelFactory<IRequestChannel> f = new BasicHttpBinding ().BuildChannelFactory<IRequestChannel> (new BindingParameterCollection ());
214 f.CreateChannel (new EndpointAddress ("stream:dummy"));
218 public void BuildChannelListenerWithoutListenUri ()
220 new BasicHttpBinding ().BuildChannelListener<IReplyChannel> (new BindingParameterCollection ());
223 // when AddressingVersion is None (in MessageVersion), then
224 // EndpointAddress.Uri and via URIs must match.
226 [ExpectedException (typeof (ArgumentException))]
227 public void EndpointAddressAndViaMustMatchOnAddressingNone ()
230 var ch = ChannelFactory<IFoo>.CreateChannel (new BasicHttpBinding (), new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort () + "/"), new Uri ("http://localhost:" + NetworkHelpers.FindFreePort () + "/HogeService"));
231 ((ICommunicationObject) ch).Close ();
232 } catch (TargetInvocationException) {
233 // we throw this exception so far. Since it is
234 // very internal difference (channel is created
235 // inside ClientRuntimeChannel.ctor() while .NET
236 // does it in ChannelFactory<T>.CreateChannel(),
237 // there is no point of treating it as failure).
238 throw new ArgumentException ();
243 public void GetPropertyMessageVersion ()
245 var be = new HttpTransportBindingElement ();
246 var mv = be.GetProperty<MessageVersion> (new BindingContext (new CustomBinding (), empty_params));
247 Assert.AreEqual (MessageVersion.Soap12WSAddressing10, mv, "#1");
251 public void GetPrpertyBindingDeliveryCapabilities ()
253 var be = new HttpTransportBindingElement ();
254 var dc = be.GetProperty<IBindingDeliveryCapabilities> (new BindingContext (new CustomBinding (), empty_params));
255 Assert.IsFalse (dc.AssuresOrderedDelivery, "#1");
256 Assert.IsFalse (dc.QueuedDelivery, "#2");
260 public void GetPrpertySecurityCapabilities ()
262 var be = new HttpTransportBindingElement ();
263 var sec = be.GetProperty<ISecurityCapabilities> (new BindingContext (new CustomBinding (), empty_params));
264 Assert.IsNotNull (sec, "#1.1");
265 Assert.AreEqual (ProtectionLevel.None, sec.SupportedRequestProtectionLevel, "#1.2");
266 Assert.AreEqual (ProtectionLevel.None, sec.SupportedResponseProtectionLevel, "#1.3");
267 Assert.IsFalse (sec.SupportsClientAuthentication, "#1.4");
268 Assert.IsFalse (sec.SupportsClientWindowsIdentity, "#1.5");
269 Assert.IsFalse (sec.SupportsServerAuthentication , "#1.6");
271 be = new HttpTransportBindingElement ();
272 be.AuthenticationScheme = AuthenticationSchemes.Negotiate;
273 sec = be.GetProperty<ISecurityCapabilities> (new BindingContext (new CustomBinding (), empty_params));
274 Assert.IsNotNull (sec, "#2.1");
275 Assert.AreEqual (ProtectionLevel.None, sec.SupportedRequestProtectionLevel, "#2.2");
276 Assert.AreEqual (ProtectionLevel.None, sec.SupportedResponseProtectionLevel, "#2.3");
277 Assert.IsTrue (sec.SupportsClientAuthentication, "#2.4");
278 Assert.IsTrue (sec.SupportsClientWindowsIdentity, "#2.5");
279 Assert.IsTrue (sec.SupportsServerAuthentication , "#2.6");
281 // almost the same, only differ at SupportsServerAuth
282 be = new HttpTransportBindingElement ();
283 be.AuthenticationScheme = AuthenticationSchemes.Ntlm;
284 sec = be.GetProperty<ISecurityCapabilities> (new BindingContext (new CustomBinding (), empty_params));
285 Assert.IsNotNull (sec, "#3.1");
286 Assert.AreEqual (ProtectionLevel.None, sec.SupportedRequestProtectionLevel, "#3.2");
287 Assert.AreEqual (ProtectionLevel.None, sec.SupportedResponseProtectionLevel, "#3.3");
288 Assert.IsTrue (sec.SupportsClientAuthentication, "#3.4");
289 Assert.IsTrue (sec.SupportsClientWindowsIdentity, "#3.5");
290 Assert.IsFalse (sec.SupportsServerAuthentication , "#3.6");
292 be = new HttpTransportBindingElement ();
293 be.AuthenticationScheme = AuthenticationSchemes.Basic;
294 sec = be.GetProperty<ISecurityCapabilities> (new BindingContext (new CustomBinding (), empty_params));
295 Assert.IsNotNull (sec, "#4.1");
296 Assert.AreEqual (ProtectionLevel.None, sec.SupportedRequestProtectionLevel, "#4.2");
297 Assert.AreEqual (ProtectionLevel.None, sec.SupportedResponseProtectionLevel, "#4.3");
298 Assert.IsTrue (sec.SupportsClientAuthentication, "#4.4");
299 Assert.IsTrue (sec.SupportsClientWindowsIdentity, "#4.5");
300 Assert.IsFalse (sec.SupportsServerAuthentication , "#4.6");
302 be = new HttpTransportBindingElement ();
303 be.AuthenticationScheme = AuthenticationSchemes.Digest;
304 sec = be.GetProperty<ISecurityCapabilities> (new BindingContext (new CustomBinding (), empty_params));
305 Assert.IsNotNull (sec, "#5.1");
306 Assert.AreEqual (ProtectionLevel.None, sec.SupportedRequestProtectionLevel, "#5.2");
307 Assert.AreEqual (ProtectionLevel.None, sec.SupportedResponseProtectionLevel, "#5.3");
308 Assert.IsTrue (sec.SupportsClientAuthentication, "#5.4");
309 Assert.IsTrue (sec.SupportsClientWindowsIdentity, "#5.5");
310 Assert.IsFalse (sec.SupportsServerAuthentication , "#5.6");
319 string DoWork (string s1, string s2);
324 #region connection test
329 [Ignore ("It somehow fails...")]
330 // It is almost identical to http-low-level-binding
331 public void LowLevelHttpConnection ()
333 HttpTransportBindingElement lel =
334 new HttpTransportBindingElement ();
337 BindingContext lbc = new BindingContext (
338 new CustomBinding (),
339 new BindingParameterCollection (),
340 new Uri ("http://localhost:" + NetworkHelpers.FindFreePort ()),
341 String.Empty, ListenUriMode.Explicit);
342 listener = lel.BuildChannelListener<IReplyChannel> (lbc);
350 Thread svc = new Thread (delegate () {
352 svcret = LowLevelHttpConnection_SetupService ();
353 } catch (Exception ex) {
354 svcret = ex.ToString ();
359 // Client code goes here.
361 HttpTransportBindingElement el =
362 new HttpTransportBindingElement ();
363 BindingContext ctx = new BindingContext (
364 new CustomBinding (),
365 new BindingParameterCollection ());
366 IChannelFactory<IRequestChannel> factory =
367 el.BuildChannelFactory<IRequestChannel> (ctx);
371 IRequestChannel request = factory.CreateChannel (
372 new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort ()));
378 Message reqmsg = Message.CreateMessage (
379 MessageVersion.Default, "Echo");
380 // sync version does not work here.
381 Message msg = request.Request (reqmsg, TimeSpan.FromSeconds (5));
383 using (XmlWriter w = XmlWriter.Create (TextWriter.Null)) {
384 msg.WriteMessage (w);
388 Assert.Fail (svcret.Length > 0 ? svcret : "service code did not finish until this test expected.");
390 if (request.State == CommunicationState.Opened)
394 if (factory.State == CommunicationState.Opened)
398 if (listener.State == CommunicationState.Opened)
403 IChannelListener<IReplyChannel> listener;
405 string LowLevelHttpConnection_SetupService ()
407 IReplyChannel reply = listener.AcceptChannel ();
409 if (!reply.WaitForRequest (TimeSpan.FromSeconds (10)))
410 return "No request reached here.";
412 svcret = "Receiving request ...";
413 RequestContext ctx = reply.ReceiveRequest ();
415 return "No request context returned.";
417 svcret = "Starting reply ...";
418 ctx.Reply (Message.CreateMessage (MessageVersion.Default, "Ack"));
427 public void ExportPolicyDefault ()
429 IPolicyExportExtension binding_element = new HttpTransportBindingElement ();
430 PolicyConversionContext conversion_context = new CustomPolicyConversionContext ();
431 binding_element.ExportPolicy (new WsdlExporter (), conversion_context);
433 PolicyAssertionCollection binding_assertions = conversion_context.GetBindingAssertions ();
434 BindingElementCollection binding_elements = conversion_context.BindingElements;
435 Assert.AreEqual (1, binding_assertions.Count, "#A0");
436 Assert.AreEqual (0, binding_elements.Count, "#A1");
438 // wsaw:UsingAddressing
439 XmlNode using_addressing_node = FindAssertion (binding_assertions, "wsaw:UsingAddressing");
440 Assert.AreEqual (true, using_addressing_node != null, "#B0");
441 Assert.AreEqual ("UsingAddressing", using_addressing_node.LocalName, "#B1");
442 Assert.AreEqual ("http://www.w3.org/2006/05/addressing/wsdl", using_addressing_node.NamespaceURI, "#B2");
443 Assert.AreEqual (0, using_addressing_node.Attributes.Count, "#B3");
444 Assert.AreEqual (0, using_addressing_node.ChildNodes.Count, "#B4");
445 Assert.AreEqual (String.Empty, using_addressing_node.InnerText, "#B5");
449 public void ExportPolicy ()
451 HttpTransportBindingElement http_binding_element = new HttpTransportBindingElement ();
454 // Specify some non-default values
456 http_binding_element.AllowCookies = !http_binding_element.AllowCookies;
457 http_binding_element.AuthenticationScheme = AuthenticationSchemes.Ntlm;
458 http_binding_element.BypassProxyOnLocal = !http_binding_element.BypassProxyOnLocal;
459 http_binding_element.HostNameComparisonMode = HostNameComparisonMode.WeakWildcard;
460 http_binding_element.KeepAliveEnabled = !http_binding_element.KeepAliveEnabled;
461 http_binding_element.ManualAddressing = !http_binding_element.ManualAddressing;
462 http_binding_element.MaxBufferPoolSize = http_binding_element.MaxBufferPoolSize / 2;
463 http_binding_element.MaxBufferSize = http_binding_element.MaxBufferSize / 2;
464 http_binding_element.MaxReceivedMessageSize = http_binding_element.MaxReceivedMessageSize / 2;
465 http_binding_element.ProxyAddress = new Uri ("http://proxyaddress.com");
466 http_binding_element.ProxyAuthenticationScheme = AuthenticationSchemes.Basic;
467 http_binding_element.Realm = "RandomRealm";
468 http_binding_element.TransferMode = TransferMode.Streamed;
469 http_binding_element.UnsafeConnectionNtlmAuthentication = !http_binding_element.UnsafeConnectionNtlmAuthentication;
470 http_binding_element.UseDefaultWebProxy = !http_binding_element.UseDefaultWebProxy;
471 http_binding_element.DecompressionEnabled = !http_binding_element.DecompressionEnabled;
472 http_binding_element.ExtendedProtectionPolicy = new ExtendedProtectionPolicy (PolicyEnforcement.WhenSupported);
475 // Actual call to ExportPolicy
477 IPolicyExportExtension binding_element = http_binding_element as IPolicyExportExtension;
478 PolicyConversionContext conversion_context = new CustomPolicyConversionContext ();
479 binding_element.ExportPolicy (new WsdlExporter (), conversion_context);
481 PolicyAssertionCollection binding_assertions = conversion_context.GetBindingAssertions ();
482 BindingElementCollection binding_elements = conversion_context.BindingElements;
483 Assert.AreEqual (2, binding_assertions.Count, "#A0");
484 Assert.AreEqual (0, binding_elements.Count, "#A1");
486 // AuthenticationScheme - the only property that causes information to be exported.
487 XmlNode authentication_node = FindAssertion (binding_assertions, "http:NtlmAuthentication");
488 Assert.AreEqual (true, authentication_node != null, "#B0");
489 Assert.AreEqual ("NtlmAuthentication", authentication_node.LocalName, "#B1");
490 Assert.AreEqual ("http://schemas.microsoft.com/ws/06/2004/policy/http", authentication_node.NamespaceURI, "#B2");
491 Assert.AreEqual (String.Empty, authentication_node.InnerText, "#B3");
492 Assert.AreEqual (0, authentication_node.Attributes.Count, "#B4");
495 // For some reason PolicyAssertionCollection.Find is not working as expected,
496 // so do the lookup manually.
497 XmlNode FindAssertion (PolicyAssertionCollection assertionCollection, string name)
499 foreach (XmlNode node in assertionCollection)
500 if (node.Name == name)
506 XmlNode FindAssertionByLocalName (PolicyAssertionCollection assertionCollection, string name)
508 foreach (XmlNode node in assertionCollection)
509 if (node.LocalName == name)
515 class MyMessageEncodingElement : MessageEncodingBindingElement {
516 MessageVersion version;
518 public MyMessageEncodingElement (MessageVersion version)
520 this.version = version;
523 public override BindingElement Clone ()
525 return new MyMessageEncodingElement (version);
527 public override MessageEncoderFactory CreateMessageEncoderFactory ()
529 throw new NotImplementedException ();
531 public override MessageVersion MessageVersion {
536 throw new NotImplementedException ();
542 public void ExportPolicy_CustomEncoding_Soap12 ()
544 HttpTransportBindingElement binding_element = new HttpTransportBindingElement ();
545 IPolicyExportExtension export_extension = binding_element as IPolicyExportExtension;
546 PolicyConversionContext conversion_context = new CustomPolicyConversionContext ();
547 conversion_context.BindingElements.Add (new MyMessageEncodingElement (MessageVersion.Soap12));
548 export_extension.ExportPolicy (new WsdlExporter (), conversion_context);
550 PolicyAssertionCollection binding_assertions = conversion_context.GetBindingAssertions ();
551 BindingElementCollection binding_elements = conversion_context.BindingElements;
552 Assert.AreEqual (0, binding_assertions.Count, "#A0");
553 Assert.AreEqual (1, binding_elements.Count, "#A1");
557 public void ExportPolicy_CustomEncoding_Soap12August2004 ()
559 HttpTransportBindingElement binding_element = new HttpTransportBindingElement ();
560 IPolicyExportExtension export_extension = binding_element as IPolicyExportExtension;
561 PolicyConversionContext conversion_context = new CustomPolicyConversionContext ();
562 conversion_context.BindingElements.Add (new MyMessageEncodingElement (MessageVersion.Soap12WSAddressingAugust2004));
563 export_extension.ExportPolicy (new WsdlExporter (), conversion_context);
565 PolicyAssertionCollection binding_assertions = conversion_context.GetBindingAssertions ();
566 BindingElementCollection binding_elements = conversion_context.BindingElements;
567 Assert.AreEqual (1, binding_assertions.Count, "#A0");
568 Assert.AreEqual (1, binding_elements.Count, "#A1");
571 XmlNode using_addressing_node = FindAssertionByLocalName (binding_assertions, "UsingAddressing");
572 Assert.AreEqual (true, using_addressing_node != null, "#B0");
573 Assert.AreEqual ("UsingAddressing", using_addressing_node.LocalName, "#B1");
574 Assert.AreEqual ("http://schemas.xmlsoap.org/ws/2004/08/addressing/policy", using_addressing_node.NamespaceURI, "#B2");
575 Assert.AreEqual (String.Empty, using_addressing_node.InnerText, "#B3");
576 Assert.AreEqual (0, using_addressing_node.Attributes.Count, "#B4");
577 Assert.AreEqual (0, using_addressing_node.ChildNodes.Count, "#B5");