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;
44 using System.Security.Authentication.ExtendedProtection;
47 namespace MonoTests.System.ServiceModel.Channels
50 public class HttpTransportBindingElementTest
52 static BindingParameterCollection empty_params =
53 new BindingParameterCollection ();
56 public void DefaultValues ()
58 HttpTransportBindingElement be =
59 new HttpTransportBindingElement ();
60 Assert.AreEqual (false, be.AllowCookies, "#1");
61 Assert.AreEqual (AuthenticationSchemes.Anonymous,
62 be.AuthenticationScheme, "#2");
63 Assert.AreEqual (false, be.BypassProxyOnLocal, "#3");
64 Assert.AreEqual (default (HostNameComparisonMode),
65 be.HostNameComparisonMode, "#4");
66 Assert.AreEqual (0x10000, be.MaxBufferSize, "#6");
67 Assert.IsNull (be.ProxyAddress, "#7");
68 Assert.AreEqual (AuthenticationSchemes.Anonymous,
69 be.ProxyAuthenticationScheme, "#8");
70 Assert.AreEqual (String.Empty, be.Realm, "#9");
71 Assert.AreEqual ("http", be.Scheme, "#10");
72 Assert.AreEqual (default (TransferMode),
73 be.TransferMode, "#11");
74 Assert.AreEqual (false,
75 be.UnsafeConnectionNtlmAuthentication, "#12");
76 Assert.AreEqual (true, be.UseDefaultWebProxy, "#13");
80 public void CanBuildChannelFactory ()
82 HttpTransportBindingElement be =
83 new HttpTransportBindingElement ();
84 BindingContext ctx = new BindingContext (
85 new CustomBinding (), empty_params);
86 Assert.IsTrue (be.CanBuildChannelFactory<IRequestChannel> (ctx), "#1");
87 Assert.IsFalse (be.CanBuildChannelFactory<IInputChannel> (ctx), "#2");
88 Assert.IsFalse (be.CanBuildChannelFactory<IReplyChannel> (ctx), "#3");
89 Assert.IsFalse (be.CanBuildChannelFactory<IOutputChannel> (ctx), "#4");
90 // seems like it does not support session channels by itself ?
91 Assert.IsFalse (be.CanBuildChannelFactory<IRequestSessionChannel> (ctx), "#5");
92 Assert.IsFalse (be.CanBuildChannelFactory<IInputSessionChannel> (ctx), "#6");
93 Assert.IsFalse (be.CanBuildChannelFactory<IReplySessionChannel> (ctx), "#7");
94 Assert.IsFalse (be.CanBuildChannelFactory<IOutputSessionChannel> (ctx), "#8");
96 // IServiceChannel is not supported
97 Assert.IsFalse (be.CanBuildChannelListener<IServiceChannel> (ctx), "#9");
101 public void CanBuildChannelListener ()
103 HttpTransportBindingElement be =
104 new HttpTransportBindingElement ();
105 BindingContext ctx = new BindingContext (
106 new CustomBinding (), empty_params);
107 Assert.IsTrue (be.CanBuildChannelListener<IReplyChannel> (ctx), "#1");
108 Assert.IsFalse (be.CanBuildChannelListener<IOutputChannel> (ctx), "#2");
109 Assert.IsFalse (be.CanBuildChannelListener<IRequestChannel> (ctx), "#3");
110 Assert.IsFalse (be.CanBuildChannelListener<IInputChannel> (ctx), "#4");
111 // seems like it does not support session channels by itself ?
112 Assert.IsFalse (be.CanBuildChannelListener<IReplySessionChannel> (ctx), "#5");
113 Assert.IsFalse (be.CanBuildChannelListener<IOutputSessionChannel> (ctx), "#6");
114 Assert.IsFalse (be.CanBuildChannelListener<IRequestSessionChannel> (ctx), "#7");
115 Assert.IsFalse (be.CanBuildChannelListener<IInputSessionChannel> (ctx), "#8");
117 // IServiceChannel is not supported
118 Assert.IsFalse (be.CanBuildChannelListener<IServiceChannel> (ctx), "#9");
122 public void BuildChannelFactory ()
124 BindingContext ctx = new BindingContext (
126 new HttpTransportBindingElement ()),
128 // returns HttpChannelFactory
129 IChannelFactory<IRequestChannel> f =
130 ctx.BuildInnerChannelFactory<IRequestChannel> ();
131 f.Open (); // required
132 IChannel c = f.CreateChannel (new EndpointAddress (
133 "http://www.mono-project.com"));
137 [ExpectedException (typeof (InvalidOperationException))]
138 public void CreateChannelWithoutOpen ()
140 BindingContext ctx = new BindingContext (
142 new HttpTransportBindingElement ()),
144 // returns HttpChannelFactory
145 IChannelFactory<IRequestChannel> f =
146 ctx.BuildInnerChannelFactory<IRequestChannel> ();
147 IChannel c = f.CreateChannel (new EndpointAddress (
148 "http://www.mono-project.com"));
152 public void BuildChannelFactoryTwoHttp ()
154 BindingContext ctx = new BindingContext (
156 new HttpTransportBindingElement (),
157 new HttpTransportBindingElement ()),
159 ctx.BuildInnerChannelFactory<IRequestChannel> ();
163 public void BuildChannelFactoryHttpThenMessage ()
165 BindingContext ctx = new BindingContext (
167 new HttpTransportBindingElement (),
168 new BinaryMessageEncodingBindingElement ()),
170 IChannelFactory<IRequestChannel> cf =
171 ctx.BuildInnerChannelFactory<IRequestChannel> ();
176 // with July CTP it still works ...
177 public void BuildChannelFactoryHttpNoMessage ()
179 BindingContext ctx = new BindingContext (
181 new HttpTransportBindingElement ()),
183 IChannelFactory<IRequestChannel> cf =
184 ctx.BuildInnerChannelFactory<IRequestChannel> ();
189 public void BuildChannelFactoryIgnoresRemaining ()
191 BindingContext ctx = new BindingContext (
193 new HttpTransportBindingElement (),
194 new InvalidBindingElement ()),
196 ctx.BuildInnerChannelFactory<IRequestChannel> ();
199 // Disable this test anytime when HttpTransportBindingElement.BuildChannelFactory() doesn't return ChannelFactoryBase`1 anymore. It's not an API requirement.
201 [ExpectedException (typeof (ArgumentNullException))]
202 public void BuildChannelFactory_CreateChannelNullVia ()
204 var ctx = new BindingContext (new CustomBinding (), empty_params);
205 var cf = new HttpTransportBindingElement ().BuildChannelFactory<IRequestChannel> (ctx);
206 Assert.IsTrue (cf is ChannelFactoryBase<IRequestChannel>, "#1");
208 cf.CreateChannel (new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort ()), null);
212 [ExpectedException (typeof (ArgumentException))]
213 public void CreateChannelInvalidScheme ()
215 IChannelFactory<IRequestChannel> f = new BasicHttpBinding ().BuildChannelFactory<IRequestChannel> (new BindingParameterCollection ());
217 f.CreateChannel (new EndpointAddress ("stream:dummy"));
221 public void BuildChannelListenerWithoutListenUri ()
223 new BasicHttpBinding ().BuildChannelListener<IReplyChannel> (new BindingParameterCollection ());
226 // when AddressingVersion is None (in MessageVersion), then
227 // EndpointAddress.Uri and via URIs must match.
229 [ExpectedException (typeof (ArgumentException))]
230 public void EndpointAddressAndViaMustMatchOnAddressingNone ()
233 var ch = ChannelFactory<IFoo>.CreateChannel (new BasicHttpBinding (), new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort () + "/"), new Uri ("http://localhost:" + NetworkHelpers.FindFreePort () + "/HogeService"));
234 ((ICommunicationObject) ch).Close ();
235 } catch (TargetInvocationException) {
236 // we throw this exception so far. Since it is
237 // very internal difference (channel is created
238 // inside ClientRuntimeChannel.ctor() while .NET
239 // does it in ChannelFactory<T>.CreateChannel(),
240 // there is no point of treating it as failure).
241 throw new ArgumentException ();
246 public void GetPropertyMessageVersion ()
248 var be = new HttpTransportBindingElement ();
249 var mv = be.GetProperty<MessageVersion> (new BindingContext (new CustomBinding (), empty_params));
250 Assert.AreEqual (MessageVersion.Soap12WSAddressing10, mv, "#1");
254 public void GetPrpertyBindingDeliveryCapabilities ()
256 var be = new HttpTransportBindingElement ();
257 var dc = be.GetProperty<IBindingDeliveryCapabilities> (new BindingContext (new CustomBinding (), empty_params));
258 Assert.IsFalse (dc.AssuresOrderedDelivery, "#1");
259 Assert.IsFalse (dc.QueuedDelivery, "#2");
263 public void GetPrpertySecurityCapabilities ()
265 var be = new HttpTransportBindingElement ();
266 var sec = be.GetProperty<ISecurityCapabilities> (new BindingContext (new CustomBinding (), empty_params));
267 Assert.IsNotNull (sec, "#1.1");
268 Assert.AreEqual (ProtectionLevel.None, sec.SupportedRequestProtectionLevel, "#1.2");
269 Assert.AreEqual (ProtectionLevel.None, sec.SupportedResponseProtectionLevel, "#1.3");
270 Assert.IsFalse (sec.SupportsClientAuthentication, "#1.4");
271 Assert.IsFalse (sec.SupportsClientWindowsIdentity, "#1.5");
272 Assert.IsFalse (sec.SupportsServerAuthentication , "#1.6");
274 be = new HttpTransportBindingElement ();
275 be.AuthenticationScheme = AuthenticationSchemes.Negotiate;
276 sec = be.GetProperty<ISecurityCapabilities> (new BindingContext (new CustomBinding (), empty_params));
277 Assert.IsNotNull (sec, "#2.1");
278 Assert.AreEqual (ProtectionLevel.None, sec.SupportedRequestProtectionLevel, "#2.2");
279 Assert.AreEqual (ProtectionLevel.None, sec.SupportedResponseProtectionLevel, "#2.3");
280 Assert.IsTrue (sec.SupportsClientAuthentication, "#2.4");
281 Assert.IsTrue (sec.SupportsClientWindowsIdentity, "#2.5");
282 Assert.IsTrue (sec.SupportsServerAuthentication , "#2.6");
284 // almost the same, only differ at SupportsServerAuth
285 be = new HttpTransportBindingElement ();
286 be.AuthenticationScheme = AuthenticationSchemes.Ntlm;
287 sec = be.GetProperty<ISecurityCapabilities> (new BindingContext (new CustomBinding (), empty_params));
288 Assert.IsNotNull (sec, "#3.1");
289 Assert.AreEqual (ProtectionLevel.None, sec.SupportedRequestProtectionLevel, "#3.2");
290 Assert.AreEqual (ProtectionLevel.None, sec.SupportedResponseProtectionLevel, "#3.3");
291 Assert.IsTrue (sec.SupportsClientAuthentication, "#3.4");
292 Assert.IsTrue (sec.SupportsClientWindowsIdentity, "#3.5");
293 Assert.IsFalse (sec.SupportsServerAuthentication , "#3.6");
295 be = new HttpTransportBindingElement ();
296 be.AuthenticationScheme = AuthenticationSchemes.Basic;
297 sec = be.GetProperty<ISecurityCapabilities> (new BindingContext (new CustomBinding (), empty_params));
298 Assert.IsNotNull (sec, "#4.1");
299 Assert.AreEqual (ProtectionLevel.None, sec.SupportedRequestProtectionLevel, "#4.2");
300 Assert.AreEqual (ProtectionLevel.None, sec.SupportedResponseProtectionLevel, "#4.3");
301 Assert.IsTrue (sec.SupportsClientAuthentication, "#4.4");
302 Assert.IsTrue (sec.SupportsClientWindowsIdentity, "#4.5");
303 Assert.IsFalse (sec.SupportsServerAuthentication , "#4.6");
305 be = new HttpTransportBindingElement ();
306 be.AuthenticationScheme = AuthenticationSchemes.Digest;
307 sec = be.GetProperty<ISecurityCapabilities> (new BindingContext (new CustomBinding (), empty_params));
308 Assert.IsNotNull (sec, "#5.1");
309 Assert.AreEqual (ProtectionLevel.None, sec.SupportedRequestProtectionLevel, "#5.2");
310 Assert.AreEqual (ProtectionLevel.None, sec.SupportedResponseProtectionLevel, "#5.3");
311 Assert.IsTrue (sec.SupportsClientAuthentication, "#5.4");
312 Assert.IsTrue (sec.SupportsClientWindowsIdentity, "#5.5");
313 Assert.IsFalse (sec.SupportsServerAuthentication , "#5.6");
322 string DoWork (string s1, string s2);
327 #region connection test
332 [Ignore ("It somehow fails...")]
333 // It is almost identical to http-low-level-binding
334 public void LowLevelHttpConnection ()
336 HttpTransportBindingElement lel =
337 new HttpTransportBindingElement ();
340 BindingContext lbc = new BindingContext (
341 new CustomBinding (),
342 new BindingParameterCollection (),
343 new Uri ("http://localhost:" + NetworkHelpers.FindFreePort ()),
344 String.Empty, ListenUriMode.Explicit);
345 listener = lel.BuildChannelListener<IReplyChannel> (lbc);
353 Thread svc = new Thread (delegate () {
355 svcret = LowLevelHttpConnection_SetupService ();
356 } catch (Exception ex) {
357 svcret = ex.ToString ();
362 // Client code goes here.
364 HttpTransportBindingElement el =
365 new HttpTransportBindingElement ();
366 BindingContext ctx = new BindingContext (
367 new CustomBinding (),
368 new BindingParameterCollection ());
369 IChannelFactory<IRequestChannel> factory =
370 el.BuildChannelFactory<IRequestChannel> (ctx);
374 IRequestChannel request = factory.CreateChannel (
375 new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort ()));
381 Message reqmsg = Message.CreateMessage (
382 MessageVersion.Default, "Echo");
383 // sync version does not work here.
384 Message msg = request.Request (reqmsg, TimeSpan.FromSeconds (5));
386 using (XmlWriter w = XmlWriter.Create (TextWriter.Null)) {
387 msg.WriteMessage (w);
391 Assert.Fail (svcret.Length > 0 ? svcret : "service code did not finish until this test expected.");
393 if (request.State == CommunicationState.Opened)
397 if (factory.State == CommunicationState.Opened)
401 if (listener.State == CommunicationState.Opened)
406 IChannelListener<IReplyChannel> listener;
408 string LowLevelHttpConnection_SetupService ()
410 IReplyChannel reply = listener.AcceptChannel ();
412 if (!reply.WaitForRequest (TimeSpan.FromSeconds (10)))
413 return "No request reached here.";
415 svcret = "Receiving request ...";
416 RequestContext ctx = reply.ReceiveRequest ();
418 return "No request context returned.";
420 svcret = "Starting reply ...";
421 ctx.Reply (Message.CreateMessage (MessageVersion.Default, "Ack"));
430 public void ExportPolicyDefault ()
432 IPolicyExportExtension binding_element = new HttpTransportBindingElement ();
433 PolicyConversionContext conversion_context = new CustomPolicyConversionContext ();
434 binding_element.ExportPolicy (new WsdlExporter (), conversion_context);
436 PolicyAssertionCollection binding_assertions = conversion_context.GetBindingAssertions ();
437 BindingElementCollection binding_elements = conversion_context.BindingElements;
438 Assert.AreEqual (1, binding_assertions.Count, "#A0");
439 Assert.AreEqual (0, binding_elements.Count, "#A1");
441 // wsaw:UsingAddressing
442 XmlNode using_addressing_node = FindAssertion (binding_assertions, "wsaw:UsingAddressing");
443 Assert.AreEqual (true, using_addressing_node != null, "#B0");
444 Assert.AreEqual ("UsingAddressing", using_addressing_node.LocalName, "#B1");
445 Assert.AreEqual ("http://www.w3.org/2006/05/addressing/wsdl", using_addressing_node.NamespaceURI, "#B2");
446 Assert.AreEqual (0, using_addressing_node.Attributes.Count, "#B3");
447 Assert.AreEqual (0, using_addressing_node.ChildNodes.Count, "#B4");
448 Assert.AreEqual (String.Empty, using_addressing_node.InnerText, "#B5");
452 public void ExportPolicy ()
454 HttpTransportBindingElement http_binding_element = new HttpTransportBindingElement ();
457 // Specify some non-default values
459 http_binding_element.AllowCookies = !http_binding_element.AllowCookies;
460 http_binding_element.AuthenticationScheme = AuthenticationSchemes.Ntlm;
461 http_binding_element.BypassProxyOnLocal = !http_binding_element.BypassProxyOnLocal;
462 http_binding_element.HostNameComparisonMode = HostNameComparisonMode.WeakWildcard;
463 http_binding_element.KeepAliveEnabled = !http_binding_element.KeepAliveEnabled;
464 http_binding_element.ManualAddressing = !http_binding_element.ManualAddressing;
465 http_binding_element.MaxBufferPoolSize = http_binding_element.MaxBufferPoolSize / 2;
466 http_binding_element.MaxBufferSize = http_binding_element.MaxBufferSize / 2;
467 http_binding_element.MaxReceivedMessageSize = http_binding_element.MaxReceivedMessageSize / 2;
468 http_binding_element.ProxyAddress = new Uri ("http://proxyaddress.com");
469 http_binding_element.ProxyAuthenticationScheme = AuthenticationSchemes.Basic;
470 http_binding_element.Realm = "RandomRealm";
471 http_binding_element.TransferMode = TransferMode.Streamed;
472 http_binding_element.UnsafeConnectionNtlmAuthentication = !http_binding_element.UnsafeConnectionNtlmAuthentication;
473 http_binding_element.UseDefaultWebProxy = !http_binding_element.UseDefaultWebProxy;
475 http_binding_element.DecompressionEnabled = !http_binding_element.DecompressionEnabled;
476 http_binding_element.ExtendedProtectionPolicy = new ExtendedProtectionPolicy (PolicyEnforcement.WhenSupported);
480 // Actual call to ExportPolicy
482 IPolicyExportExtension binding_element = http_binding_element as IPolicyExportExtension;
483 PolicyConversionContext conversion_context = new CustomPolicyConversionContext ();
484 binding_element.ExportPolicy (new WsdlExporter (), conversion_context);
486 PolicyAssertionCollection binding_assertions = conversion_context.GetBindingAssertions ();
487 BindingElementCollection binding_elements = conversion_context.BindingElements;
488 Assert.AreEqual (2, binding_assertions.Count, "#A0");
489 Assert.AreEqual (0, binding_elements.Count, "#A1");
491 // AuthenticationScheme - the only property that causes information to be exported.
492 XmlNode authentication_node = FindAssertion (binding_assertions, "http:NtlmAuthentication");
493 Assert.AreEqual (true, authentication_node != null, "#B0");
494 Assert.AreEqual ("NtlmAuthentication", authentication_node.LocalName, "#B1");
495 Assert.AreEqual ("http://schemas.microsoft.com/ws/06/2004/policy/http", authentication_node.NamespaceURI, "#B2");
496 Assert.AreEqual (String.Empty, authentication_node.InnerText, "#B3");
497 Assert.AreEqual (0, authentication_node.Attributes.Count, "#B4");
500 // For some reason PolicyAssertionCollection.Find is not working as expected,
501 // so do the lookup manually.
502 XmlNode FindAssertion (PolicyAssertionCollection assertionCollection, string name)
504 foreach (XmlNode node in assertionCollection)
505 if (node.Name == name)
511 XmlNode FindAssertionByLocalName (PolicyAssertionCollection assertionCollection, string name)
513 foreach (XmlNode node in assertionCollection)
514 if (node.LocalName == name)
520 class MyMessageEncodingElement : MessageEncodingBindingElement {
521 MessageVersion version;
523 public MyMessageEncodingElement (MessageVersion version)
525 this.version = version;
528 public override BindingElement Clone ()
530 return new MyMessageEncodingElement (version);
532 public override MessageEncoderFactory CreateMessageEncoderFactory ()
534 throw new NotImplementedException ();
536 public override MessageVersion MessageVersion {
541 throw new NotImplementedException ();
547 public void ExportPolicy_CustomEncoding_Soap12 ()
549 HttpTransportBindingElement binding_element = new HttpTransportBindingElement ();
550 IPolicyExportExtension export_extension = binding_element as IPolicyExportExtension;
551 PolicyConversionContext conversion_context = new CustomPolicyConversionContext ();
552 conversion_context.BindingElements.Add (new MyMessageEncodingElement (MessageVersion.Soap12));
553 export_extension.ExportPolicy (new WsdlExporter (), conversion_context);
555 PolicyAssertionCollection binding_assertions = conversion_context.GetBindingAssertions ();
556 BindingElementCollection binding_elements = conversion_context.BindingElements;
557 Assert.AreEqual (0, binding_assertions.Count, "#A0");
558 Assert.AreEqual (1, binding_elements.Count, "#A1");
562 public void ExportPolicy_CustomEncoding_Soap12August2004 ()
564 HttpTransportBindingElement binding_element = new HttpTransportBindingElement ();
565 IPolicyExportExtension export_extension = binding_element as IPolicyExportExtension;
566 PolicyConversionContext conversion_context = new CustomPolicyConversionContext ();
567 conversion_context.BindingElements.Add (new MyMessageEncodingElement (MessageVersion.Soap12WSAddressingAugust2004));
568 export_extension.ExportPolicy (new WsdlExporter (), conversion_context);
570 PolicyAssertionCollection binding_assertions = conversion_context.GetBindingAssertions ();
571 BindingElementCollection binding_elements = conversion_context.BindingElements;
572 Assert.AreEqual (1, binding_assertions.Count, "#A0");
573 Assert.AreEqual (1, binding_elements.Count, "#A1");
576 XmlNode using_addressing_node = FindAssertionByLocalName (binding_assertions, "UsingAddressing");
577 Assert.AreEqual (true, using_addressing_node != null, "#B0");
578 Assert.AreEqual ("UsingAddressing", using_addressing_node.LocalName, "#B1");
579 Assert.AreEqual ("http://schemas.xmlsoap.org/ws/2004/08/addressing/policy", using_addressing_node.NamespaceURI, "#B2");
580 Assert.AreEqual (String.Empty, using_addressing_node.InnerText, "#B3");
581 Assert.AreEqual (0, using_addressing_node.Attributes.Count, "#B4");
582 Assert.AreEqual (0, using_addressing_node.ChildNodes.Count, "#B5");