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;
51 bool exclusiveAddressUse
= true;
53 bool wantsToListen
= true;
55 HttpServerTransportSink sink
;
56 ChannelDataStore channelData
;
57 RemotingHttpListener listener
;
61 public HttpServerChannel ()
63 //DONT START SERVER, EVEN THOUGH ALL OTHER CONSTRUCTORS DO
67 public HttpServerChannel (int port
)
73 [MonoTODO ("Handle the listen property")]
74 public HttpServerChannel (IDictionary properties
, IServerChannelSinkProvider sinkProvider
)
77 if (properties
!= null) {
78 foreach (DictionaryEntry property
in properties
) {
79 switch ((string)property
.Key
) {
81 //NOTE: matching MS behaviour: throws InvalidCastException, allows null
82 this.name
= (string)property
.Value
;
85 this.priority
= Convert
.ToInt32 (property
.Value
);
88 this.port
= Convert
.ToInt32 (property
.Value
);
90 case "suppressChannelData":
91 this.suppressChannelData
= Convert
.ToBoolean (property
.Value
);
94 bindAddress
= IPAddress
.Parse ((string)property
.Value
);
97 this.useIPAddress
= Convert
.ToBoolean (property
.Value
);
100 this.machineName
= (string)property
.Value
;
103 this.wantsToListen
= Convert
.ToBoolean (property
.Value
);
106 case "exclusiveAddressUse":
107 this.exclusiveAddressUse
= Convert
.ToBoolean (property
.Value
);
114 BuildSink (sinkProvider
);
117 public HttpServerChannel (string name
, int port
)
118 : this (name
, port
, null)
122 public HttpServerChannel (string name
, int port
, IServerChannelSinkProvider sinkProvider
)
126 BuildSink (sinkProvider
);
129 void BuildSink (IServerChannelSinkProvider sinkProvider
)
131 //resolve names (modified from TcpChannel)
132 if (machineName
== null) {
134 if (!bindAddress
.Equals (IPAddress
.Any
)) {
135 machineName
= bindAddress
.ToString ();
137 IPHostEntry hostEntry
= Dns
.Resolve (Dns
.GetHostName ());
138 if (hostEntry
.AddressList
.Length
== 0)
139 throw new RemotingException ("IP address could not be determined for this host");
140 // We DON'T want to take the resolved address from the hostEntry, since the socket
141 // should still bind to IPAddress.Any, so that we get the loopback too
142 machineName
= hostEntry
.AddressList
[0].ToString ();
145 IPHostEntry hostEntry
= Dns
.GetHostByName (Dns
.GetHostName ());
146 bindAddress
= hostEntry
.AddressList
[0];
147 machineName
= hostEntry
.HostName
;
151 if (sinkProvider
== null) {
152 //build a default chain that can handle wsdl, soap, binary
153 sinkProvider
= new SdlChannelSinkProvider (); //for wsdl
154 sinkProvider
.Next
= new SoapServerFormatterSinkProvider ();
155 sinkProvider
.Next
.Next
= new BinaryServerFormatterSinkProvider ();
158 //MS compat: channelData is null when port < 0
160 channelData
= new ChannelDataStore (null);
161 IServerChannelSinkProvider provider
= sinkProvider
;
162 while (provider
!= null) {
163 provider
.GetChannelData (channelData
);
164 provider
= provider
.Next
;
168 //create the sink chain and add an HTTP sink
169 IServerChannelSink nextSink
= ChannelServices
.CreateServerChannelSinkChain (sinkProvider
, this);
170 sink
= new HttpServerTransportSink (nextSink
);
172 // BaseChannelWithProperties wants this to be set with the chain
173 base.SinksWithProperties
= nextSink
;
175 StartListening (null);
182 public string ChannelName
187 public int ChannelPriority
189 get { return priority; }
192 public string Parse (string url
, out string objectURI
)
194 return HttpChannel
.ParseInternal (url
, out objectURI
);
199 public string GetChannelUri ()
201 return "http://" + machineName
+ ":" + port
;
204 #region IChannelReceiver (: IChannel)
206 public object ChannelData
210 return suppressChannelData
? null
215 //from TcpServerChannel
216 public virtual string[] GetUrlsForUri (string objectUri
)
218 if (!objectUri
.StartsWith ("/"))
219 objectUri
= "/" + objectUri
;
221 if (channelData
== null || channelData
.ChannelUris
== null || channelData
.ChannelUris
.Length
< 1) {
222 return new string[] { GetChannelUri () + objectUri }
;
225 string[] channelUris
= channelData
.ChannelUris
;
226 string[] result
= new string[channelUris
.Length
];
228 for (int i
= 0; i
< channelUris
.Length
; i
++)
229 result
[i
] = channelUris
[i
] + objectUri
;
234 public void StartListening (object data
)
236 if (listener
!= null)
243 listener
= new RemotingHttpListener (bindAddress
, port
, sink
);
244 } catch (Exception
) {
245 if (listener
!= null) {
253 port
= listener
.AssignedPort
;
255 channelData
.ChannelUris
= new string [] { GetChannelUri () }
;
256 wantsToListen
= false;
259 public void StopListening (object data
)
261 if (listener
!= null) {
269 #region BaseChannelWithProperties overrides
271 public override object this[object key
]
273 get { return base[key]; }
274 set { base[key] = value; }
277 public override ICollection Keys
279 get { return new object[0]; }
284 #region IChannelReceiverHook
286 public void AddHookChannelUri (string channelUri
)
288 string [] newUris
= new string[1] { channelUri }
;
289 if (channelData
== null)
290 channelData
= new ChannelDataStore (newUris
);
292 channelData
.ChannelUris
= newUris
;
293 wantsToListen
= false;
296 public string ChannelScheme
298 get { return "http"; }
301 public IServerChannelSink ChannelSinkChain
303 get { return (IServerChannelSink)base.SinksWithProperties; }
306 public bool WantsToListen
308 get { return wantsToListen; }
310 throw new NotImplementedException ("Behaviour not yet determined");