// (C) 2003 Martin Willemoes Hansen
//
+//
+// 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.Collections;
using System.IO;
namespace System.Runtime.Remoting.Channels.Http
{
-
-
-
-
-
- public class HttpClientChannel : IChannelSender,IChannel
+ public class HttpClientChannel : BaseChannelWithProperties, IChannelSender,IChannel
{
// Property Keys (purposely all lower-case)
private const String ProxyNameKey = "proxyname";
private const String ProxyPortKey = "proxyport";
- // If above keys get modified be sure to modify, the KeySet property on this
- // class.
- private static ICollection s_keySet = null;
-
-
// Settings
private int _channelPriority = 1; // channel priority
private String _channelName = "http"; // channel name
private int _clientConnectionLimit = 0; // bump connection limit to at least this number (only meaningful if > 0)
private bool _bUseDefaultCredentials = false; // should default credentials be used?
- private IClientChannelSinkProvider _sinkProvider = null; // sink chain provider
-
- private IMessageSink _msgSink;
-
-
+ private IClientChannelSinkProvider _sinkProvider = null; // sink chain provider
public HttpClientChannel()
{
-
- SetupProvider(_sinkProvider);
+ SetupProvider (null,null);
}
-
-
public HttpClientChannel(String name, IClientChannelSinkProvider sinkProvider)
{
if(name != null)
_channelName = name;
- SetupProvider(sinkProvider);
+ SetupProvider (sinkProvider, null);
}
-
// constructor used by config file
public HttpClientChannel(IDictionary properties, IClientChannelSinkProvider sinkProvider)
{
- if(properties!=null)
- foreach(DictionaryEntry Dict in properties)
+ if (properties != null)
{
- switch(Dict.Key.ToString())
+ foreach(DictionaryEntry Dict in properties)
{
- case "name":
- _channelName = Dict.Value.ToString();
- break;
- case "priority":
- _channelPriority = Convert.ToInt32(Dict.Value);
- break;
- case "clientConnectionLimit":
- _clientConnectionLimit = Convert.ToInt32(Dict.Value);
- break;
- case "proxyName":
- _proxyName = Dict.Value.ToString();
- break;
- case "proxyPort":
- _proxyPort = Convert.ToInt32(Dict.Value);
- break;
- case "useDefaultCredentials":
- _bUseDefaultCredentials = Convert.ToBoolean(Dict.Value);
- break;
+ switch(Dict.Key.ToString())
+ {
+ case "name":
+ _channelName = Dict.Value.ToString();
+ break;
+ case "priority":
+ _channelPriority = Convert.ToInt32(Dict.Value);
+ break;
+ case "clientConnectionLimit":
+ _clientConnectionLimit = Convert.ToInt32(Dict.Value);
+ break;
+ case "proxyName":
+ _proxyName = Dict.Value.ToString();
+ break;
+ case "proxyPort":
+ _proxyPort = Convert.ToInt32(Dict.Value);
+ break;
+ case "useDefaultCredentials":
+ _bUseDefaultCredentials = Convert.ToBoolean(Dict.Value);
+ break;
+ }
}
}
- //UpdateProxy();
- SetupProvider(sinkProvider);
-
+
+ SetupProvider (sinkProvider, properties);
}
-
- /*<note><private>
- private void SetupChannel()
- {
- } */
-
public int ChannelPriority
{
get { return _channelPriority; }
public virtual IMessageSink CreateMessageSink(String url, Object remoteChannelData, out String objectURI)
{
- if (url == null && remoteChannelData != null && remoteChannelData as IChannelDataStore != null )
+ if ((url == null || !HttpHelper.StartsWithHttp (url)) && remoteChannelData != null && remoteChannelData as IChannelDataStore != null )
{
IChannelDataStore ds = (IChannelDataStore) remoteChannelData;
url = ds.ChannelUris[0];
if(url != null && HttpHelper.StartsWithHttp(url))
{
HttpHelper.Parse(url, out objectURI);
- _msgSink = (IMessageSink) _sinkProvider.CreateSink(this,url,remoteChannelData);
+ IMessageSink msgSink = (IMessageSink) _sinkProvider.CreateSink(this,url,remoteChannelData);
- if(_msgSink !=null )
+ if(msgSink !=null )
SetServicePoint(url);
- return _msgSink;
+ return msgSink;
}
else
{
objectURI = null;
return null;
}
-
}
private void UpdateProxy()
ServicePoint sp = ServicePointManager.FindServicePoint(channelURI,ProxyObject);
if(_clientConnectionLimit> 0)
sp.ConnectionLimit = _clientConnectionLimit;
-
-
- }
-
-
+ }
internal IWebProxy ProxyObject { get { return _proxyObject; } }
internal bool UseDefaultCredentials { get { return _bUseDefaultCredentials; } }
- private void SetupProvider(IClientChannelSinkProvider sinkProvider)
+ private void SetupProvider (IClientChannelSinkProvider sinkProvider, IDictionary properties)
{
+ if (properties == null) properties = new Hashtable ();
+ HttpClientTransportSinkProvider httpSink = new HttpClientTransportSinkProvider (properties);
+ SinksWithProperties = httpSink;
+
if(sinkProvider == null)
{
- //_sinkProvider = new SoapClientFormatterSinkProvider();
- _sinkProvider = new BinaryClientFormatterSinkProvider();
- _sinkProvider.Next = new HttpClientTransportSinkProvider();
+ _sinkProvider = new SoapClientFormatterSinkProvider();
+ _sinkProvider.Next = httpSink;
}
else
{
dummySinkProvider = dummySinkProvider.Next;
}
- dummySinkProvider.Next = new HttpClientTransportSinkProvider();
+ dummySinkProvider.Next = httpSink;
}
-
+ }
+
+ public override object this [object key]
+ {
+ get { return Properties[key]; }
+ set { Properties[key] = value; }
+ }
+
+ public override ICollection Keys
+ {
+ get { return Properties.Keys; }
}
}
- internal class HttpClientTransportSinkProvider : IClientChannelSinkProvider
+ internal class HttpClientTransportSinkProvider : IClientChannelSinkProvider, IChannelSinkBase
{
- internal HttpClientTransportSinkProvider()
+ IDictionary _properties;
+
+ internal HttpClientTransportSinkProvider (IDictionary properties)
{
+ _properties = properties;
}
public IClientChannelSink CreateSink(IChannelSender channel, String url,
get { return null; }
set { throw new NotSupportedException(); }
}
+
+ public IDictionary Properties
+ {
+ get { return _properties; }
+ }
+
} // class HttpClientTransportSinkProvider
private const String s_defaultVerb = "POST";
private static String s_userAgent =
- "Mozilla/4.0+(compatible; MSIE 6.0; Windows " +
- "; MS .NET Remoting; MS .NET CLR " + System.Environment.Version.ToString() + " )";
+ "Mono Remoting Client (Mono CLR " + System.Environment.Version.ToString() + ")";
// Property keys (purposely all lower-case)
private const String UserNameKey = "username";
// settings
private bool _useChunked = false;
- private bool _useKeepAlive = true;
+// private bool _useKeepAlive = true;
internal HttpClientTransportSink(HttpClientChannel channel, String channelURI) : base()
{
ITransportHeaders requestHeaders, Stream requestStream,
out ITransportHeaders responseHeaders, out Stream responseStream)
{
-
-
string url = null;
- string uri = (string)requestHeaders[CommonTransportKeys.RequestUri];
+ string uri = ((IMethodCallMessage)msg).Uri;
+ requestHeaders [CommonTransportKeys.RequestUri] = uri;
CreateUrl(uri,out url);
- HttpWebRequest httpWebRequest = CreateWebRequest(url,requestHeaders,requestStream);
+ HttpWebRequest httpWebRequest = CreateWebRequest (url,requestHeaders,requestStream);
- SendAndRecieve(httpWebRequest,out responseHeaders,out responseStream);
+ SendAndRecieve (httpWebRequest,out responseHeaders,out responseStream);
}
public void AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg,
ITransportHeaders headers, Stream stream)
{
- try
- {
- string url = null;
- string uri = (string)headers[CommonTransportKeys.RequestUri];
- CreateUrl(uri,out url);
-
- HttpWebRequest httpWebRequest = CreateWebRequest(url,headers,stream);
- RequestState reqState = new RequestState(httpWebRequest,sinkStack);
+ string url = null;
+ string uri = ((IMethodCallMessage)msg).Uri;
+ headers [CommonTransportKeys.RequestUri] = uri;
+ CreateUrl(uri,out url);
- httpWebRequest.BeginGetResponse(new AsyncCallback(AsyncRequestHandler),reqState);
+ HttpWebRequest httpWebRequest = CreateWebRequest(url,headers,stream);
+ RequestState reqState = new RequestState(httpWebRequest,sinkStack);
- }
- catch
- {
- Console.WriteLine("Error Sending Async Request");
- }
+ httpWebRequest.BeginGetResponse(new AsyncCallback(AsyncRequestHandler),reqState);
}
private void AsyncRequestHandler(IAsyncResult ar)
RequestState reqState = (RequestState) ar.AsyncState;
HttpWebRequest httpWebRequest = reqState.webRquest;
+ IClientChannelSinkStack sinkStack = reqState.sinkStack;
try
{
httpWebResponse = (HttpWebResponse) httpWebRequest.EndGetResponse(ar);
-
- Stream responseStream ;
- ITransportHeaders responseHeaders;
-
- IClientChannelSinkStack sinkStack = reqState.sinkStack;
+ }
+ catch (WebException ex)
+ {
+ httpWebResponse = ex.Response as HttpWebResponse;
+ if (httpWebResponse == null) sinkStack.DispatchException (ex);
+ }
- responseStream = new MemoryStream();
- HttpHelper.CopyStream(httpWebResponse.GetResponseStream(),ref responseStream);
-
-
- responseHeaders = new TransportHeaders();
-
- for(int i=0; i < httpWebResponse.Headers.Count; ++i)
- responseHeaders[httpWebResponse.Headers.Keys[i].ToString()] = httpWebResponse.Headers[i].ToString();
+ Stream responseStream;
+ ITransportHeaders responseHeaders;
- sinkStack.AsyncProcessResponse(responseHeaders,responseStream);
-
- }
- catch
+ try
{
- Console.WriteLine("Error Recieving Async Response");
+ ReceiveResponse (httpWebResponse, out responseHeaders, out responseStream);
+ sinkStack.AsyncProcessResponse(responseHeaders,responseStream);
}
- finally
+ catch (Exception ex)
{
- if(httpWebResponse!=null)
- httpWebResponse.Close();
+ sinkStack.DispatchException (ex);
}
}
}
} // this[]
-
public override ICollection Keys
{
get
}
}
-
-
-
private void UpdateProxy()
{
// If the user values for the proxy object are valid , then the proxy
private HttpWebRequest CreateWebRequest(string url, ITransportHeaders requestHeaders, Stream requestStream)
{
-
-
-
-
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);;
request.AllowAutoRedirect = _bAllowAutoRedirect;
request.ContentLength = requestStream.Length;
//request.Expect = "100-Continue";
//This caused us some troubles with the HttpWebResponse class
- //maybe its fixed now.
+ //maybe its fixed now. TODO
//request.KeepAlive = _useKeepAlive;
request.KeepAlive = false;;
}
Stream reqStream = request.GetRequestStream();
- HttpHelper.CopyStream(requestStream,ref reqStream);
-
- reqStream.Close();
+ try {
+ HttpHelper.CopyStream(requestStream, reqStream);
+ } finally {
+ reqStream.Close();
+ }
return request;
}
- private bool SendAndRecieve(HttpWebRequest httpRequest,out ITransportHeaders responseHeaders,out Stream responseStream)
+ private void SendAndRecieve(HttpWebRequest httpRequest,out ITransportHeaders responseHeaders,out Stream responseStream)
{
responseStream = null;
responseHeaders = null;
HttpWebResponse httpWebResponse = null;
- bool returnValue = false;
-
-
try
{
httpWebResponse = (HttpWebResponse)httpRequest.GetResponse();
+ }
+ catch (WebException ex)
+ {
+ httpWebResponse = ex.Response as HttpWebResponse;
+ if (httpWebResponse == null || httpWebResponse.StatusCode == HttpStatusCode.InternalServerError) throw ex;
+ }
- responseStream = new MemoryStream();
- HttpHelper.CopyStream(httpWebResponse.GetResponseStream(),ref responseStream);
+ ReceiveResponse (httpWebResponse, out responseHeaders, out responseStream);
+ }
+ private void ReceiveResponse (HttpWebResponse httpWebResponse, out ITransportHeaders responseHeaders, out Stream responseStream)
+ {
+ responseHeaders = new TransportHeaders();
+ Stream webStream = httpWebResponse.GetResponseStream();
+
+ try
+ {
+ if (httpWebResponse.ContentLength != -1)
+ {
+ byte[] buffer = new byte [httpWebResponse.ContentLength];
+ int nr = 0;
+ while (nr < buffer.Length) {
+ int pr = webStream.Read (buffer, nr, buffer.Length - nr);
+ if (pr == 0) throw new RemotingException ("Connection closed");
+ nr += pr;
+ }
+ responseStream = new MemoryStream (buffer);
+ }
+ else
+ {
+ responseStream = new MemoryStream();
+ HttpHelper.CopyStream(webStream, responseStream);
+ }
- responseHeaders = new TransportHeaders();
-
-
//Use the two commented lines below instead of the 3 below lines when HttpWebResponse
//class is fully implemented in order to support custom headers
//for(int i=0; i < httpWebResponse.Headers.Count; ++i)
// responseHeaders[httpWebResponse.Headers.Keys[i].ToString()] = httpWebResponse.Headers[i].ToString();
-
+
responseHeaders["Content-Type"] = httpWebResponse.ContentType;
responseHeaders["Server"] = httpWebResponse.Server;
responseHeaders["Content-Length"] = httpWebResponse.ContentLength;
-
- returnValue =true;
- }
- catch(Exception e)
- {
-
- Console.WriteLine(e);
- returnValue = false;
}
-
finally
{
- if(httpWebResponse!=null)
- httpWebResponse.Close();
+ webStream.Close ();
+ httpWebResponse.Close();
}
- return returnValue;
}
private void ProcessErrorCode()