2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Runtime.Remoting / System.Runtime.Remoting.Channels.Http / HttpClientChannel.cs
blobb8eea16af24e96b25c823005d7d38e7c4b4b2574
1 //
2 // HttpClientChannel.cs
3 //
4 // Author:
5 // Michael Hutchinson <mhutchinson@novell.com>
6 //
7 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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;
30 using System.Net;
31 using System.Collections;
32 using System.Globalization;
33 using System.Runtime.Remoting.Messaging;
35 namespace System.Runtime.Remoting.Channels.Http
38 public class HttpClientChannel : BaseChannelWithProperties,
39 IChannel, IChannelSender
40 #if NET_2_0
41 , ISecurableChannel
42 #endif
44 string name = "http client";
45 int priority = 1;
48 // names and (some) default values fromhttp://msdn.microsoft.com/en-us/library/bb187435(VS.85).aspx
49 // other values guessed from defaults of HttpWebResponse
50 string machineName = null;
51 bool allowAutoRedirect = true; //FIXME: what's the default? true/false?
52 int clientConnectionLimit = 2;
53 string connectionGroupName = null;
54 ICredentials credentials = null;
55 string domain = null;
56 string password = null;
57 string proxyName = null;
58 int proxyPort = -1;
59 Uri proxyUri = null;
60 string servicePrincipalName = null;
61 int timeout = -1;
62 bool unsafeAuthenticatedConnectionSharing = false;
63 // according to docs, should be true if useDefaultCredentials true or
64 // credentials is CredentialCache.DefaultCredentials
65 bool useAuthenticatedConnectionSharing = false;
66 bool useDefaultCredentials = false;
67 string username = null;
69 bool isSecured = false;
71 IClientChannelSinkProvider sinkProvider;
73 #region Constructors
75 public HttpClientChannel ()
77 BuildSink (null);
80 [MonoTODO ("Handle the machineName, proxyName, proxyPort, servicePrincipalName, " +
81 "useAuthenticatedConnectionSharing properties")]
82 public HttpClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
84 if (properties != null) {
85 foreach (DictionaryEntry property in properties) {
86 switch ((string)property.Key) {
87 case "name":
88 //NOTE: matching MS behaviour: throws InvalidCastException, allows null
89 this.name = (string)property.Value;
90 break;
91 case "priority":
92 this.priority = Convert.ToInt32 (property.Value);
93 break;
94 case "machineName":
95 this.machineName = (string)property.Value;
96 break;
97 case "allowAutoRedirect":
98 this.allowAutoRedirect = Convert.ToBoolean (property.Value);
99 break;
100 case "clientConnectionLimit":
101 this.clientConnectionLimit = Convert.ToInt32 (property.Value);
102 break;
103 case "connectionGroupName":
104 this.connectionGroupName = (string)property.Value;
105 break;
106 case "credentials":
107 this.credentials = (ICredentials)property.Value;
108 if (this.credentials == CredentialCache.DefaultCredentials)
109 useAuthenticatedConnectionSharing = true;
110 break;
111 case "domain":
112 this.domain = (string)property.Value;
113 break;
114 case "password":
115 this.password = (string)property.Value;
116 break;
117 case "proxyName":
118 this.proxyName = (string)property.Value;
119 break;
120 case "proxyPort":
121 this.proxyPort = Convert.ToInt32 (property.Value);
122 break;
123 case "servicePrincipalName":
124 this.servicePrincipalName = (string)property.Value;
125 break;
126 case "timeout":
127 this.timeout = Convert.ToInt32 (property.Value);
128 break;
129 case "unsafeAuthenticatedConnectionSharing":
130 this.unsafeAuthenticatedConnectionSharing = Convert.ToBoolean (property.Value);
131 break;
132 case "useAuthenticatedConnectionSharing":
133 this.useAuthenticatedConnectionSharing = Convert.ToBoolean (property.Value);
134 break;
135 case "useDefaultCredentials":
136 this.useDefaultCredentials = Convert.ToBoolean (property.Value);
137 if (useDefaultCredentials)
138 useAuthenticatedConnectionSharing = true;
139 break;
140 case "username":
141 this.username = (string)property.Value;
142 break;
147 BuildSink (sinkProvider);
150 public HttpClientChannel (string name, IClientChannelSinkProvider sinkProvider)
152 this.name = name;
153 BuildSink (sinkProvider);
156 void BuildSink (IClientChannelSinkProvider sinkProvider)
158 if (sinkProvider == null) {
159 //according to docs, defaults to SOAP if no other sink provided
160 sinkProvider = new SoapClientFormatterSinkProvider ();
163 this.sinkProvider = sinkProvider;
165 //add HTTP sink at the end of the chain
166 while (sinkProvider.Next != null) sinkProvider = sinkProvider.Next;
167 sinkProvider.Next = new HttpClientTransportSinkProvider ();
169 // LAMESPEC: BaseChannelWithProperties wants SinksWithProperties to be set with the sink chain
170 // BUT MS' HttpClientChannel does not set it (inspected from HttpClientChannel subclass)
173 #endregion
175 #region BaseChannelWithProperties overrides
177 public override object this[object key]
181 switch (key as string) {
182 case "proxyport":
183 return proxyPort;
184 case "proxyname":
185 return proxyName;
187 return null;
191 switch (key as string) {
192 case "proxyport":
193 proxyPort = Convert.ToInt32 (value);
194 ConstructProxy ();
195 return;
196 case "proxyname":
197 proxyName = (string)value;
198 ConstructProxy ();
199 return;
201 //ignore other values, MS does so
205 public override ICollection Keys
209 return new string[] {
210 "proxyname",
211 "proxyport"
216 void ConstructProxy ()
218 if (proxyName != null && proxyPort > 0)
219 proxyUri = new Uri (proxyName + ":" + proxyPort);
222 #endregion
224 #region IChannel
226 public string ChannelName
228 get { return name; }
231 public int ChannelPriority
233 get { return priority; }
236 public string Parse (string url, out string objectURI)
238 return HttpChannel.ParseInternal (url, out objectURI);
241 #endregion
243 #region IChannelSender (: IChannel)
245 public virtual IMessageSink CreateMessageSink (string url, object remoteChannelData, out string objectURI)
247 //Mostly copied from TcpClientChannel
248 if (url == null || Parse (url, out objectURI) == null) {
249 if (remoteChannelData != null) {
250 IChannelDataStore ds = remoteChannelData as IChannelDataStore;
251 if (ds != null && ds.ChannelUris.Length > 0)
252 url = ds.ChannelUris[0];
253 else {
254 objectURI = null;
255 return null;
259 if (Parse (url, out objectURI) == null)
260 return null;
263 object newSink = sinkProvider.CreateSink (this, url, remoteChannelData);
264 if (newSink is IMessageSink) {
265 return (IMessageSink) newSink;
266 } else {
267 throw new RemotingException ("First channel sink must implement IMessageSink");
271 #endregion
273 #if NET_2_0
274 #region ISecurableChannel
276 public bool IsSecured
278 get { return isSecured; }
279 set {
280 throw new NotImplementedException ("Unable to determine expected behaviour yet.");
284 #endregion
285 #endif
287 #region Internal properties
289 internal string MachineName {
290 get { return machineName; }
292 internal bool AllowAutoRedirect {
293 get { return allowAutoRedirect; }
295 internal int ClientConnectionLimit {
296 get { return clientConnectionLimit; }
298 internal string ConnectionGroupName {
299 get { return connectionGroupName; }
301 internal ICredentials Credentials {
302 get { return credentials; }
304 internal string Domain {
305 get { return domain; }
307 internal string Password {
308 get { return password; }
310 internal string Username {
311 get { return username; }
313 internal string ProxyName {
314 get { return proxyName; }
316 internal int ProxyPort {
317 get { return proxyPort; }
319 internal Uri ProxyUri {
320 get { return proxyUri; }
322 internal string ServicePrincipalName {
323 get { return servicePrincipalName; }
325 internal int Timeout {
326 get { return timeout; }
328 internal bool UnsafeAuthenticatedConnectionSharing {
329 get { return unsafeAuthenticatedConnectionSharing; }
331 internal bool UseAuthenticatedConnectionSharing {
332 get { return useAuthenticatedConnectionSharing; }
334 internal bool UseDefaultCredentials {
335 get { return useDefaultCredentials; }
338 #endregion