2 // HttpServerChannel.cs
5 // Michael Hutchinson <mhutchinson@novell.com>
7 // Copyright (C) 2008 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.
30 using System.Collections;
31 using System.Globalization;
32 using System.Threading;
33 using System.Runtime.Remoting.MetadataServices;
34 using System.Runtime.Remoting.Messaging;
36 namespace System.Runtime.Remoting.Channels.Http
39 public class HttpServerChannel : BaseChannelWithProperties,
40 IChannel, IChannelReceiver, IChannelReceiverHook
42 string name = "http server";
45 string machineName = null;
46 IPAddress bindAddress = IPAddress.Any;
47 int port = -1; // querying GetChannelUri () on .NET indicates this is the default value
48 bool suppressChannelData = false;
49 bool useIPAddress = true;
50 bool wantsToListen = true;
52 HttpServerTransportSink sink;
53 ChannelDataStore channelData;
54 RemotingHttpListener listener;
58 public HttpServerChannel ()
60 //DONT START SERVER, EVEN THOUGH ALL OTHER CONSTRUCTORS DO
64 public HttpServerChannel (int port)
70 [MonoTODO ("Handle the listen property")]
71 public HttpServerChannel (IDictionary properties, IServerChannelSinkProvider sinkProvider)
74 if (properties != null) {
75 foreach (DictionaryEntry property in properties) {
76 switch ((string)property.Key) {
78 //NOTE: matching MS behaviour: throws InvalidCastException, allows null
79 this.name = (string)property.Value;
82 this.priority = Convert.ToInt32 (property.Value);
85 this.port = Convert.ToInt32 (property.Value);
87 case "suppressChannelData":
88 this.suppressChannelData = Convert.ToBoolean (property.Value);
91 bindAddress = IPAddress.Parse ((string)property.Value);
94 this.useIPAddress = Convert.ToBoolean (property.Value);
97 this.machineName = (string)property.Value;
100 this.wantsToListen = Convert.ToBoolean (property.Value);
106 BuildSink (sinkProvider);
109 public HttpServerChannel (string name, int port)
110 : this (name, port, null)
114 public HttpServerChannel (string name, int port, IServerChannelSinkProvider sinkProvider)
118 BuildSink (sinkProvider);
121 void BuildSink (IServerChannelSinkProvider sinkProvider)
123 //resolve names (modified from TcpChannel)
124 if (machineName == null) {
126 if (!bindAddress.Equals (IPAddress.Any)) {
127 machineName = bindAddress.ToString ();
129 IPHostEntry hostEntry = Dns.Resolve (Dns.GetHostName ());
130 if (hostEntry.AddressList.Length == 0)
131 throw new RemotingException ("IP address could not be determined for this host");
132 // We DON'T want to take the resolved address from the hostEntry, since the socket
133 // should still bind to IPAddress.Any, so that we get the loopback too
134 machineName = hostEntry.AddressList[0].ToString ();
137 IPHostEntry hostEntry = Dns.GetHostByName (Dns.GetHostName ());
138 bindAddress = hostEntry.AddressList[0];
139 machineName = hostEntry.HostName;
143 if (sinkProvider == null) {
144 //build a default chain that can handle wsdl, soap, binary
145 sinkProvider = new SdlChannelSinkProvider (); //for wsdl
146 sinkProvider.Next = new SoapServerFormatterSinkProvider ();
147 sinkProvider.Next.Next = new BinaryServerFormatterSinkProvider ();
150 //MS compat: channelData is null when port < 0
152 channelData = new ChannelDataStore (null);
153 IServerChannelSinkProvider provider = sinkProvider;
154 while (provider != null) {
155 provider.GetChannelData (channelData);
156 provider = provider.Next;
160 //create the sink chain and add an HTTP sink
161 IServerChannelSink nextSink = ChannelServices.CreateServerChannelSinkChain (sinkProvider, this);
162 sink = new HttpServerTransportSink (nextSink);
164 // BaseChannelWithProperties wants this to be set with the chain
165 base.SinksWithProperties = nextSink;
167 StartListening (null);
174 public string ChannelName
179 public int ChannelPriority
181 get { return priority; }
184 public string Parse (string url, out string objectURI)
186 return HttpChannel.ParseInternal (url, out objectURI);
191 public string GetChannelUri ()
193 return "http://" + machineName + ":" + port;
196 #region IChannelReceiver (: IChannel)
198 public object ChannelData
202 return suppressChannelData ? null
207 //from TcpServerChannel
208 public virtual string[] GetUrlsForUri (string objectUri)
210 if (!objectUri.StartsWith ("/"))
211 objectUri = "/" + objectUri;
213 if (channelData == null || channelData.ChannelUris == null || channelData.ChannelUris.Length < 1) {
214 return new string[] { GetChannelUri () + objectUri };
217 string[] channelUris = channelData.ChannelUris;
218 string[] result = new string[channelUris.Length];
220 for (int i = 0; i < channelUris.Length; i++)
221 result[i] = channelUris[i] + objectUri;
226 public void StartListening (object data)
228 if (listener != null)
235 listener = new RemotingHttpListener (bindAddress, port, sink);
236 } catch (Exception) {
237 if (listener != null) {
245 port = listener.AssignedPort;
247 channelData.ChannelUris = new string [] { GetChannelUri () };
248 wantsToListen = false;
251 public void StopListening (object data)
253 if (listener != null) {
261 #region BaseChannelWithProperties overrides
263 public override object this[object key]
265 get { return base[key]; }
266 set { base[key] = value; }
269 public override ICollection Keys
271 get { return new object[0]; }
276 #region IChannelReceiverHook
278 public void AddHookChannelUri (string channelUri)
280 string [] newUris = new string[1] { channelUri };
281 if (channelData == null)
282 channelData = new ChannelDataStore (newUris);
284 channelData.ChannelUris = newUris;
285 wantsToListen = false;
288 public string ChannelScheme
290 get { return "http"; }
293 public IServerChannelSink ChannelSinkChain
295 get { return (IServerChannelSink)base.SinksWithProperties; }
298 public bool WantsToListen
300 get { return wantsToListen; }
302 throw new NotImplementedException ("Behaviour not yet determined");