3c1f479b9d
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
338 lines
9.0 KiB
C#
338 lines
9.0 KiB
C#
//
|
|
// HttpClientChannel.cs
|
|
//
|
|
// Author:
|
|
// Michael Hutchinson <mhutchinson@novell.com>
|
|
//
|
|
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.Net;
|
|
using System.Collections;
|
|
using System.Globalization;
|
|
using System.Runtime.Remoting.Messaging;
|
|
|
|
namespace System.Runtime.Remoting.Channels.Http
|
|
{
|
|
|
|
public class HttpClientChannel : BaseChannelWithProperties,
|
|
IChannel, IChannelSender
|
|
, ISecurableChannel
|
|
{
|
|
string name = "http client";
|
|
int priority = 1;
|
|
|
|
|
|
// names and (some) default values fromhttp://msdn.microsoft.com/en-us/library/bb187435(VS.85).aspx
|
|
// other values guessed from defaults of HttpWebResponse
|
|
string machineName = null;
|
|
bool allowAutoRedirect = true; //FIXME: what's the default? true/false?
|
|
int clientConnectionLimit = 2;
|
|
string connectionGroupName = null;
|
|
ICredentials credentials = null;
|
|
string domain = null;
|
|
string password = null;
|
|
string proxyName = null;
|
|
int proxyPort = -1;
|
|
Uri proxyUri = null;
|
|
string servicePrincipalName = null;
|
|
int timeout = -1;
|
|
bool unsafeAuthenticatedConnectionSharing = false;
|
|
// according to docs, should be true if useDefaultCredentials true or
|
|
// credentials is CredentialCache.DefaultCredentials
|
|
bool useAuthenticatedConnectionSharing = false;
|
|
bool useDefaultCredentials = false;
|
|
string username = null;
|
|
|
|
bool isSecured = false;
|
|
|
|
IClientChannelSinkProvider sinkProvider;
|
|
|
|
#region Constructors
|
|
|
|
public HttpClientChannel ()
|
|
{
|
|
BuildSink (null);
|
|
}
|
|
|
|
[MonoTODO ("Handle the machineName, proxyName, proxyPort, servicePrincipalName, " +
|
|
"useAuthenticatedConnectionSharing properties")]
|
|
public HttpClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
|
|
{
|
|
if (properties != null) {
|
|
foreach (DictionaryEntry property in properties) {
|
|
switch ((string)property.Key) {
|
|
case "name":
|
|
//NOTE: matching MS behaviour: throws InvalidCastException, allows null
|
|
this.name = (string)property.Value;
|
|
break;
|
|
case "priority":
|
|
this.priority = Convert.ToInt32 (property.Value);
|
|
break;
|
|
case "machineName":
|
|
this.machineName = (string)property.Value;
|
|
break;
|
|
case "allowAutoRedirect":
|
|
this.allowAutoRedirect = Convert.ToBoolean (property.Value);
|
|
break;
|
|
case "clientConnectionLimit":
|
|
this.clientConnectionLimit = Convert.ToInt32 (property.Value);
|
|
break;
|
|
case "connectionGroupName":
|
|
this.connectionGroupName = (string)property.Value;
|
|
break;
|
|
case "credentials":
|
|
this.credentials = (ICredentials)property.Value;
|
|
if (this.credentials == CredentialCache.DefaultCredentials)
|
|
useAuthenticatedConnectionSharing = true;
|
|
break;
|
|
case "domain":
|
|
this.domain = (string)property.Value;
|
|
break;
|
|
case "password":
|
|
this.password = (string)property.Value;
|
|
break;
|
|
case "proxyName":
|
|
this.proxyName = (string)property.Value;
|
|
break;
|
|
case "proxyPort":
|
|
this.proxyPort = Convert.ToInt32 (property.Value);
|
|
break;
|
|
case "servicePrincipalName":
|
|
this.servicePrincipalName = (string)property.Value;
|
|
break;
|
|
case "timeout":
|
|
this.timeout = Convert.ToInt32 (property.Value);
|
|
break;
|
|
case "unsafeAuthenticatedConnectionSharing":
|
|
this.unsafeAuthenticatedConnectionSharing = Convert.ToBoolean (property.Value);
|
|
break;
|
|
case "useAuthenticatedConnectionSharing":
|
|
this.useAuthenticatedConnectionSharing = Convert.ToBoolean (property.Value);
|
|
break;
|
|
case "useDefaultCredentials":
|
|
this.useDefaultCredentials = Convert.ToBoolean (property.Value);
|
|
if (useDefaultCredentials)
|
|
useAuthenticatedConnectionSharing = true;
|
|
break;
|
|
case "username":
|
|
this.username = (string)property.Value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
BuildSink (sinkProvider);
|
|
}
|
|
|
|
public HttpClientChannel (string name, IClientChannelSinkProvider sinkProvider)
|
|
{
|
|
this.name = name;
|
|
BuildSink (sinkProvider);
|
|
}
|
|
|
|
void BuildSink (IClientChannelSinkProvider sinkProvider)
|
|
{
|
|
if (sinkProvider == null) {
|
|
//according to docs, defaults to SOAP if no other sink provided
|
|
sinkProvider = new SoapClientFormatterSinkProvider ();
|
|
}
|
|
|
|
this.sinkProvider = sinkProvider;
|
|
|
|
//add HTTP sink at the end of the chain
|
|
while (sinkProvider.Next != null) sinkProvider = sinkProvider.Next;
|
|
sinkProvider.Next = new HttpClientTransportSinkProvider ();
|
|
|
|
// LAMESPEC: BaseChannelWithProperties wants SinksWithProperties to be set with the sink chain
|
|
// BUT MS' HttpClientChannel does not set it (inspected from HttpClientChannel subclass)
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region BaseChannelWithProperties overrides
|
|
|
|
public override object this[object key]
|
|
{
|
|
get
|
|
{
|
|
switch (key as string) {
|
|
case "proxyport":
|
|
return proxyPort;
|
|
case "proxyname":
|
|
return proxyName;
|
|
}
|
|
return null;
|
|
}
|
|
set
|
|
{
|
|
switch (key as string) {
|
|
case "proxyport":
|
|
proxyPort = Convert.ToInt32 (value);
|
|
ConstructProxy ();
|
|
return;
|
|
case "proxyname":
|
|
proxyName = (string)value;
|
|
ConstructProxy ();
|
|
return;
|
|
}
|
|
//ignore other values, MS does so
|
|
}
|
|
}
|
|
|
|
public override ICollection Keys
|
|
{
|
|
get
|
|
{
|
|
return new string[] {
|
|
"proxyname",
|
|
"proxyport"
|
|
};
|
|
}
|
|
}
|
|
|
|
void ConstructProxy ()
|
|
{
|
|
if (proxyName != null && proxyPort > 0)
|
|
proxyUri = new Uri (proxyName + ":" + proxyPort);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IChannel
|
|
|
|
public string ChannelName
|
|
{
|
|
get { return name; }
|
|
}
|
|
|
|
public int ChannelPriority
|
|
{
|
|
get { return priority; }
|
|
}
|
|
|
|
public string Parse (string url, out string objectURI)
|
|
{
|
|
return HttpChannel.ParseInternal (url, out objectURI);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IChannelSender (: IChannel)
|
|
|
|
public virtual IMessageSink CreateMessageSink (string url, object remoteChannelData, out string objectURI)
|
|
{
|
|
//Mostly copied from TcpClientChannel
|
|
if (url == null || Parse (url, out objectURI) == null) {
|
|
if (remoteChannelData != null) {
|
|
IChannelDataStore ds = remoteChannelData as IChannelDataStore;
|
|
if (ds != null && ds.ChannelUris.Length > 0)
|
|
url = ds.ChannelUris[0];
|
|
else {
|
|
objectURI = null;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
if (Parse (url, out objectURI) == null)
|
|
return null;
|
|
}
|
|
|
|
object newSink = sinkProvider.CreateSink (this, url, remoteChannelData);
|
|
if (newSink is IMessageSink) {
|
|
return (IMessageSink) newSink;
|
|
} else {
|
|
throw new RemotingException ("First channel sink must implement IMessageSink");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ISecurableChannel
|
|
|
|
public bool IsSecured
|
|
{
|
|
get { return isSecured; }
|
|
set {
|
|
throw new NotImplementedException ("Unable to determine expected behaviour yet.");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Internal properties
|
|
|
|
internal string MachineName {
|
|
get { return machineName; }
|
|
}
|
|
internal bool AllowAutoRedirect {
|
|
get { return allowAutoRedirect; }
|
|
}
|
|
internal int ClientConnectionLimit {
|
|
get { return clientConnectionLimit; }
|
|
}
|
|
internal string ConnectionGroupName {
|
|
get { return connectionGroupName; }
|
|
}
|
|
internal ICredentials Credentials {
|
|
get { return credentials; }
|
|
}
|
|
internal string Domain {
|
|
get { return domain; }
|
|
}
|
|
internal string Password {
|
|
get { return password; }
|
|
}
|
|
internal string Username {
|
|
get { return username; }
|
|
}
|
|
internal string ProxyName {
|
|
get { return proxyName; }
|
|
}
|
|
internal int ProxyPort {
|
|
get { return proxyPort; }
|
|
}
|
|
internal Uri ProxyUri {
|
|
get { return proxyUri; }
|
|
}
|
|
internal string ServicePrincipalName {
|
|
get { return servicePrincipalName; }
|
|
}
|
|
internal int Timeout {
|
|
get { return timeout; }
|
|
}
|
|
internal bool UnsafeAuthenticatedConnectionSharing {
|
|
get { return unsafeAuthenticatedConnectionSharing; }
|
|
}
|
|
internal bool UseAuthenticatedConnectionSharing {
|
|
get { return useAuthenticatedConnectionSharing; }
|
|
}
|
|
internal bool UseDefaultCredentials {
|
|
get { return useDefaultCredentials; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|