source: TFP-WebServer/SpaceWizards.HttpListener/src/System/Net/Managed/HttpEndPointManager.cs

Last change on this file was 377, checked in by alloc, 2 years ago

Made SpaceWizards.HttpListener compilable against .NET 4.8 with preprocessor define UNITY_NETFRAMEWORK

File size: 7.8 KB
Line 
1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3
4//
5// System.Net.HttpEndPointManager
6//
7// Author:
8// Gonzalo Paniagua Javier (gonzalo@ximian.com)
9//
10// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
11//
12// Permission is hereby granted, free of charge, to any person obtaining
13// a copy of this software and associated documentation files (the
14// "Software"), to deal in the Software without restriction, including
15// without limitation the rights to use, copy, modify, merge, publish,
16// distribute, sublicense, and/or sell copies of the Software, and to
17// permit persons to whom the Software is furnished to do so, subject to
18// the following conditions:
19//
20// The above copyright notice and this permission notice shall be
21// included in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30//
31
32// ReSharper disable RedundantAssignment
33#pragma warning disable CS8602
34
35using System;
36using System.Collections;
37using System.Collections.Generic;
38using System.Linq;
39using System.Net;
40using System.Net.Sockets;
41
42namespace SpaceWizards.HttpListener
43{
44 internal sealed class HttpEndPointManager
45 {
46 private static Dictionary<IPAddress, Dictionary<int, HttpEndPointListener>> s_ipEndPoints = new Dictionary<IPAddress, Dictionary<int, HttpEndPointListener>>();
47
48 private HttpEndPointManager()
49 {
50 }
51
52 public static void AddListener(HttpListener listener)
53 {
54 List<string> added = new List<string>();
55 try
56 {
57 lock ((s_ipEndPoints as ICollection).SyncRoot)
58 {
59 foreach (string prefix in listener.Prefixes)
60 {
61 AddPrefixInternal(prefix, listener);
62 added.Add(prefix);
63 }
64 }
65 }
66 catch
67 {
68 foreach (string prefix in added)
69 {
70 RemovePrefix(prefix, listener);
71 }
72 throw;
73 }
74 }
75
76 public static void AddPrefix(string prefix, HttpListener listener)
77 {
78 lock ((s_ipEndPoints as ICollection).SyncRoot)
79 {
80 AddPrefixInternal(prefix, listener);
81 }
82 }
83
84 private static void AddPrefixInternal(string p, HttpListener listener)
85 {
86 ListenerPrefix lp = new ListenerPrefix(p);
87 if (lp.Host != "*" && lp.Host != "+" && Uri.CheckHostName(lp.Host) == UriHostNameType.Unknown)
88 throw new HttpListenerException((int)HttpStatusCode.BadRequest, SR.net_listener_host);
89
90 if (lp.Port <= 0 || lp.Port >= 65536)
91 throw new HttpListenerException((int)HttpStatusCode.BadRequest, SR.net_invalid_port);
92
93 if (lp.Path!.Contains('%'))
94 throw new HttpListenerException((int)HttpStatusCode.BadRequest, SR.net_invalid_path);
95
96 if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1)
97 throw new HttpListenerException((int)HttpStatusCode.BadRequest, SR.net_invalid_path);
98
99 // listens on all the interfaces if host name cannot be parsed by IPAddress.
100 foreach (HttpEndPointListener epl in GetEPListener(lp.Host!, lp.Port, listener, lp.Secure))
101 {
102 epl.AddPrefix(lp, listener);
103 }
104 }
105
106 private static IEnumerable<HttpEndPointListener> GetEPListener(string host, int port, HttpListener listener, bool secure)
107 {
108 IPAddress[] addresses;
109 if (host == "*" || host == "+")
110 {
111 addresses = new []{IPAddress.Any, IPAddress.IPv6Any};
112 }
113 else
114 {
115#if UNITY_NETFRAMEWORK
116 if (host.Length > 1 && host[0] == '[' && host[host.Length - 1] == ']')
117 host = host.Substring (1, host.Length - 2);
118#else
119 if (host.StartsWith('[') && host.EndsWith(']'))
120 host = host[1..^1];
121#endif
122
123 const int NotSupportedErrorCode = 50;
124 try
125 {
126 addresses = Dns.GetHostAddresses(host);
127 }
128 catch
129 {
130 // Throw same error code as windows, request is not supported.
131 throw new HttpListenerException(NotSupportedErrorCode, SR.net_listener_not_supported);
132 }
133
134 if (addresses.Any(a => a.Equals(IPAddress.IPv6Any) || a.Equals(IPAddress.Any)))
135 {
136 // Don't support listening to 0.0.0.0, match windows behavior.
137 throw new HttpListenerException(NotSupportedErrorCode, SR.net_listener_not_supported);
138 }
139 }
140
141 foreach (var addr in addresses)
142 {
143 Dictionary<int, HttpEndPointListener>? p = null;
144 if (s_ipEndPoints.ContainsKey(addr))
145 {
146 p = s_ipEndPoints[addr];
147 }
148 else
149 {
150 p = new Dictionary<int, HttpEndPointListener>();
151 s_ipEndPoints[addr] = p;
152 }
153
154 HttpEndPointListener? epl = null;
155 if (p.ContainsKey(port))
156 {
157 epl = p[port];
158 }
159 else
160 {
161 try
162 {
163 epl = new HttpEndPointListener(listener, addr, port, secure);
164 }
165 catch (SocketException ex)
166 {
167 throw new HttpListenerException(ex.ErrorCode, ex.Message);
168 }
169 p[port] = epl;
170 }
171
172 yield return epl;
173 }
174 }
175
176 public static void RemoveEndPoint(HttpEndPointListener epl, IPEndPoint ep)
177 {
178 lock ((s_ipEndPoints as ICollection).SyncRoot)
179 {
180 Dictionary<int, HttpEndPointListener>? p = null;
181 p = s_ipEndPoints[ep.Address];
182 p.Remove(ep.Port);
183 if (p.Count == 0)
184 {
185 s_ipEndPoints.Remove(ep.Address);
186 }
187 epl.Close();
188 }
189 }
190
191 public static void RemoveListener(HttpListener listener)
192 {
193 lock ((s_ipEndPoints as ICollection).SyncRoot)
194 {
195 foreach (string prefix in listener.Prefixes)
196 {
197 RemovePrefixInternal(prefix, listener);
198 }
199 }
200 }
201
202 public static void RemovePrefix(string prefix, HttpListener listener)
203 {
204 lock ((s_ipEndPoints as ICollection).SyncRoot)
205 {
206 RemovePrefixInternal(prefix, listener);
207 }
208 }
209
210 private static void RemovePrefixInternal(string prefix, HttpListener listener)
211 {
212 ListenerPrefix lp = new ListenerPrefix(prefix);
213 if (lp.Path!.Contains('%'))
214 return;
215
216 if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1)
217 return;
218
219 foreach (HttpEndPointListener epl in GetEPListener(lp.Host!, lp.Port, listener, lp.Secure))
220 {
221 epl.RemovePrefix(lp, listener);
222 }
223 }
224 }
225}
Note: See TracBrowser for help on using the repository browser.