Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / System.Runtime.Remoting / System.Runtime.Remoting.Channels.Http / HttpClientChannel.cs
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.
27 //
28
29 using System;
30 using System.Net;
31 using System.Collections;
32 using System.Globalization;
33 using System.Runtime.Remoting.Messaging;
34
35 namespace System.Runtime.Remoting.Channels.Http
36 {
37
38         public class HttpClientChannel : BaseChannelWithProperties,
39                 IChannel, IChannelSender
40                 , ISecurableChannel
41         {
42                 string name = "http client";
43                 int priority = 1;
44
45
46                 // names and (some) default values fromhttp://msdn.microsoft.com/en-us/library/bb187435(VS.85).aspx
47                 // other values guessed from defaults of HttpWebResponse
48                 string machineName = null;
49                 bool allowAutoRedirect = true; //FIXME: what's the default? true/false?
50                 int clientConnectionLimit = 2;
51                 string connectionGroupName = null;
52                 ICredentials credentials = null;
53                 string domain = null;
54                 string password = null;
55                 string proxyName = null;
56                 int proxyPort = -1;
57                 Uri proxyUri = null;
58                 string servicePrincipalName = null;
59                 int timeout = -1;
60                 bool unsafeAuthenticatedConnectionSharing = false;
61                 // according to docs, should be true if useDefaultCredentials true or 
62                 // credentials is CredentialCache.DefaultCredentials
63                 bool useAuthenticatedConnectionSharing = false;
64                 bool useDefaultCredentials = false;
65                 string username = null;
66                 
67                 bool isSecured = false;
68
69                 IClientChannelSinkProvider sinkProvider;
70
71                 #region Constructors
72
73                 public HttpClientChannel ()
74                 {
75                         BuildSink (null);
76                 }
77                 
78                 [MonoTODO ("Handle the machineName, proxyName, proxyPort, servicePrincipalName, " + 
79                         "useAuthenticatedConnectionSharing properties")]
80                 public HttpClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
81                 {
82                         if (properties != null) {
83                                 foreach (DictionaryEntry property in properties) {
84                                         switch ((string)property.Key) {
85                                         case "name":
86                                                 //NOTE: matching MS behaviour: throws InvalidCastException, allows null
87                                                 this.name = (string)property.Value;
88                                                 break;
89                                         case "priority":
90                                                 this.priority = Convert.ToInt32 (property.Value);
91                                                 break;
92                                         case "machineName":
93                                                 this.machineName = (string)property.Value;
94                                                 break;
95                                         case "allowAutoRedirect":
96                                                 this.allowAutoRedirect = Convert.ToBoolean (property.Value);
97                                                 break;
98                                         case "clientConnectionLimit":
99                                                 this.clientConnectionLimit = Convert.ToInt32 (property.Value);
100                                                 break;
101                                         case "connectionGroupName":
102                                                 this.connectionGroupName = (string)property.Value;
103                                                 break;
104                                         case "credentials":
105                                                 this.credentials = (ICredentials)property.Value;
106                                                 if (this.credentials == CredentialCache.DefaultCredentials)
107                                                         useAuthenticatedConnectionSharing = true;
108                                                 break;
109                                         case "domain":
110                                                 this.domain = (string)property.Value;
111                                                 break;
112                                         case "password":
113                                                 this.password = (string)property.Value;
114                                                 break;
115                                         case "proxyName":
116                                                 this.proxyName = (string)property.Value;
117                                                 break;
118                                         case "proxyPort":
119                                                 this.proxyPort = Convert.ToInt32 (property.Value);
120                                                 break;
121                                         case "servicePrincipalName":
122                                                 this.servicePrincipalName = (string)property.Value;
123                                                 break;
124                                         case "timeout":
125                                                 this.timeout = Convert.ToInt32 (property.Value);
126                                                 break;
127                                         case "unsafeAuthenticatedConnectionSharing":
128                                                 this.unsafeAuthenticatedConnectionSharing = Convert.ToBoolean (property.Value);
129                                                 break;
130                                         case "useAuthenticatedConnectionSharing":
131                                                 this.useAuthenticatedConnectionSharing = Convert.ToBoolean (property.Value);
132                                                 break;
133                                         case "useDefaultCredentials":
134                                                 this.useDefaultCredentials = Convert.ToBoolean (property.Value);
135                                                 if (useDefaultCredentials)
136                                                         useAuthenticatedConnectionSharing = true;
137                                                 break;
138                                         case "username":
139                                                 this.username = (string)property.Value;
140                                                 break;
141                                         }
142                                 }
143                         }
144
145                         BuildSink (sinkProvider);
146                 }
147
148                 public HttpClientChannel (string name, IClientChannelSinkProvider sinkProvider)
149                 {
150                         this.name = name;
151                         BuildSink (sinkProvider);
152                 }
153
154                 void BuildSink (IClientChannelSinkProvider sinkProvider)
155                 {
156                         if (sinkProvider == null) {
157                                 //according to docs, defaults to SOAP if no other sink provided
158                                 sinkProvider = new SoapClientFormatterSinkProvider ();
159                         }
160
161                         this.sinkProvider = sinkProvider;
162
163                         //add HTTP sink at the end of the chain
164                         while (sinkProvider.Next != null) sinkProvider = sinkProvider.Next;
165                         sinkProvider.Next = new HttpClientTransportSinkProvider ();
166
167                         // LAMESPEC: BaseChannelWithProperties wants SinksWithProperties to be set with the sink chain
168                         // BUT MS' HttpClientChannel does not set it (inspected from HttpClientChannel subclass)
169                 }
170
171                 #endregion
172
173                 #region BaseChannelWithProperties overrides
174
175                 public override object this[object key]
176                 {
177                         get
178                         {
179                                 switch (key as string) {
180                                 case "proxyport":
181                                         return proxyPort;
182                                 case "proxyname":
183                                         return proxyName;
184                                 }
185                                 return null;
186                         }
187                         set
188                         {
189                                 switch (key as string) {
190                                 case "proxyport":
191                                         proxyPort = Convert.ToInt32 (value);
192                                         ConstructProxy ();
193                                         return;
194                                 case "proxyname":
195                                         proxyName = (string)value;
196                                         ConstructProxy ();
197                                         return;
198                                 }
199                                 //ignore other values, MS does so
200                         }
201                 }
202
203                 public override ICollection Keys
204                 {
205                         get
206                         {
207                                 return new string[] {
208                                         "proxyname",
209                                         "proxyport"
210                                 };
211                         }
212                 }
213
214                 void ConstructProxy ()
215                 {
216                         if (proxyName != null && proxyPort > 0)
217                                 proxyUri = new Uri (proxyName + ":" + proxyPort);
218                 }
219
220                 #endregion
221
222                 #region IChannel
223
224                 public string ChannelName
225                 {
226                         get { return name; }
227                 }
228
229                 public int ChannelPriority
230                 {
231                         get { return priority; }
232                 }
233
234                 public string Parse (string url, out string objectURI)
235                 {
236                         return HttpChannel.ParseInternal (url, out objectURI);
237                 }
238
239                 #endregion
240
241                 #region IChannelSender (: IChannel)
242
243                 public virtual IMessageSink CreateMessageSink (string url, object remoteChannelData, out string objectURI)
244                 {
245                         //Mostly copied from TcpClientChannel
246                         if (url == null || Parse (url, out objectURI) == null) {
247                                 if (remoteChannelData != null) {
248                                         IChannelDataStore ds = remoteChannelData as IChannelDataStore;
249                                         if (ds != null && ds.ChannelUris.Length > 0)
250                                                 url = ds.ChannelUris[0];
251                                         else {
252                                                 objectURI = null;
253                                                 return null;
254                                         }
255                                 }
256
257                                 if (Parse (url, out objectURI) == null)
258                                         return null;
259                         }
260                         
261                         object newSink = sinkProvider.CreateSink (this, url, remoteChannelData);
262                         if (newSink is IMessageSink) {
263                                 return (IMessageSink) newSink;
264                         } else {
265                                 throw new RemotingException ("First channel sink must implement IMessageSink");
266                         }
267                 }
268
269                 #endregion
270                 
271                 #region ISecurableChannel
272                 
273                 public bool IsSecured
274                 {
275                         get { return isSecured; }
276                         set {
277                                 throw new NotImplementedException ("Unable to determine expected behaviour yet.");
278                         }
279                 }
280                 
281                 #endregion
282                 
283                 #region Internal properties
284                 
285                 internal string MachineName {
286                         get { return machineName; }
287                 }
288                 internal bool AllowAutoRedirect {
289                         get { return allowAutoRedirect; }
290                 }
291                 internal int ClientConnectionLimit {
292                         get { return clientConnectionLimit; }
293                 }
294                 internal string ConnectionGroupName {
295                         get { return connectionGroupName; }
296                 }
297                 internal ICredentials Credentials {
298                         get { return credentials; }
299                 }
300                 internal string Domain {
301                         get { return domain; }
302                 }
303                 internal string Password {
304                         get { return password; }
305                 }
306                 internal string Username {
307                         get { return username; }
308                 }
309                 internal string ProxyName {
310                         get { return proxyName; }
311                 }
312                 internal int ProxyPort {
313                         get { return proxyPort; }
314                 }
315                 internal Uri ProxyUri {
316                         get { return proxyUri; }
317                 }
318                 internal string ServicePrincipalName {
319                         get { return servicePrincipalName; }
320                 }
321                 internal int Timeout {
322                         get { return timeout; }
323                 }
324                 internal bool UnsafeAuthenticatedConnectionSharing {
325                         get { return unsafeAuthenticatedConnectionSharing; }
326                 }
327                 internal bool UseAuthenticatedConnectionSharing {
328                         get { return useAuthenticatedConnectionSharing; }
329                 }
330                 internal bool UseDefaultCredentials {
331                         get { return useDefaultCredentials; }
332                 }
333                 
334                 #endregion
335
336         }
337 }