Merge pull request #1222 from LogosBible/uri-trycreate
[mono.git] / mcs / class / System.Runtime.Remoting / System.Runtime.Remoting.Channels.Http / HttpChannel.cs
1 //
2 // HttpChannel.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.Collections;
30 using System.Runtime.Remoting.Messaging;
31
32 namespace System.Runtime.Remoting.Channels.Http
33 {
34
35         public class HttpChannel : BaseChannelWithProperties,
36                 IChannel, IChannelReceiver, IChannelReceiverHook, IChannelSender
37                 , ISecurableChannel
38         {
39                 HttpClientChannel client;
40                 HttpServerChannel server;
41                 string name = "http";
42
43                 #region Constructors
44
45                 public HttpChannel ()
46                 {
47                         client = new HttpClientChannel ();
48                         server = new HttpServerChannel ();
49                 }
50
51                 public HttpChannel (int port)
52                 {
53                         client = new HttpClientChannel ();
54                         server = new HttpServerChannel (port);
55                 }
56
57                 public HttpChannel (IDictionary properties,
58                         IClientChannelSinkProvider clientSinkProvider,
59                         IServerChannelSinkProvider serverSinkProvider)
60                 {
61                         if (properties != null && properties.Contains ("name")) {
62                                 this.name = (string)properties["name"];
63                         }
64
65                         client = new HttpClientChannel (properties, clientSinkProvider);
66                         server = new HttpServerChannel (properties, serverSinkProvider);
67                 }
68
69                 #endregion
70
71                 #region BaseChannelWithProperties overrides
72
73                 public override object this[object key]
74                 {
75                         get { return Properties[key]; }
76                         set { Properties[key] = value; }
77                 }
78
79                 public override ICollection Keys
80                 {
81                         get { return Properties.Keys; }
82                 }
83
84                 public override IDictionary Properties
85                 {
86                         get
87                         {
88                                 return new AggregateDictionary (new IDictionary[] {
89                                         client.Properties,
90                                         server.Properties
91                                 });
92                         }
93                 }
94
95                 #endregion
96
97                 #region IChannel
98
99                 public string ChannelName
100                 {
101                         get { return name; }
102                 }
103
104                 public int ChannelPriority
105                 {
106                         get { return server.ChannelPriority; }
107                 }
108
109                 public string Parse (string url, out string objectURI)
110                 {
111                         return ParseInternal (url, out objectURI);
112                 }
113
114                 internal static string ParseInternal (string url, out string objectURI)
115                 {
116                         if (url == null)
117                                 throw new ArgumentNullException ("url");
118                         
119                         // format: "http://host:port/path/to/object"
120                         objectURI = null;
121                         
122                         // url needs to be at least "http:" or "https:"
123                         if (url.Length < 5 ||
124                             (url[0] != 'H' && url[0] != 'h') ||
125                             (url[1] != 'T' && url[1] != 't') ||
126                             (url[2] != 'T' && url[2] != 't') ||
127                             (url[3] != 'P' && url[3] != 'p'))
128                                 return null;
129                         
130                         int protolen;
131                         if (url[4] == 'S' || url[4] == 's') {
132                                 if (url.Length < 6)
133                                         return null;
134                                 
135                                 protolen = 5;
136                         } else {
137                                 protolen = 4;
138                         }
139                         
140                         if (url[protolen] != ':')
141                                 return null;
142                         
143                         // "http:" and "https:" are acceptable inputs
144                         if (url.Length == protolen + 1)
145                                 return url;
146                         
147                         // protocol must be followed by "//"
148                         if (url.Length < protolen + 3 || url[protolen + 1] != '/' || url[protolen + 2] != '/')
149                                 return null;
150                         
151                         // "http://" and "https://" are acceptable inputs
152                         if (url.Length == protolen + 3)
153                                 return url;
154                         
155                         int slash = url.IndexOf ('/', protolen + 3);
156                         if (slash == -1)
157                                 return url;
158                                 
159                         objectURI = url.Substring (slash);
160
161                         return url.Substring (0, slash);
162                 }
163
164                 #endregion
165
166                 #region IChannelReceiver (: IChannel)
167
168                 public object ChannelData
169                 {
170                         get { return server.ChannelData; }
171                 }
172
173                 public string[] GetUrlsForUri (string objectURI)
174                 {
175                         return server.GetUrlsForUri (objectURI);
176                 }
177
178                 public void StartListening (object data)
179                 {
180                         server.StartListening (data);
181                 }
182
183                 public void StopListening (object data)
184                 {
185                         server.StopListening (data);
186                 }
187
188                 #endregion
189
190                 #region IChannelReceiverHook
191
192                 public void AddHookChannelUri (string channelUri)
193                 {
194                         server.AddHookChannelUri (channelUri);
195                 }
196
197                 public string ChannelScheme
198                 {
199                         get { return server.ChannelScheme; }
200                 }
201
202                 public IServerChannelSink ChannelSinkChain
203                 {
204                         get { return server.ChannelSinkChain; }
205                 }
206
207                 public bool WantsToListen
208                 {
209                         get { return server.WantsToListen; }
210                         set { server.WantsToListen = value; }
211                 }
212
213                 #endregion
214
215                 #region IChannelSender (: IChannel)
216
217                 public IMessageSink CreateMessageSink (string url, object remoteChannelData, out string objectURI)
218                 {
219                         return client.CreateMessageSink (url, remoteChannelData, out objectURI);
220                 }
221
222                 #endregion
223
224                 #region ISecurableChannel
225
226                 public bool IsSecured
227                 {
228                         get { return client.IsSecured; }
229                         set { client.IsSecured = value; }
230                 }
231
232                 #endregion
233         }
234 }