public ISessionContext CreateSessionContext() { return(new SessionContext(Cryptography.CreateRandom(4))); }
public void Start() { var Success = false; try { IsRunningValue.Update ( b => { if (b) { throw new InvalidOperationException(); } if (BindingsValue.Length == 0) { throw new Exception("NoValidBinding"); } ListeningTaskTokenSource = new CancellationTokenSource(); var ListeningTaskToken = ListeningTaskTokenSource.Token; foreach (var Binding in BindingsValue) { Listener.Prefixes.Add(Binding); } if (UnauthenticatedSessionIdleTimeoutValue.HasValue) { SetTimer(Listener, UnauthenticatedSessionIdleTimeoutValue.Value); } Action <HttpListenerContext> PurifyContext = ListenerContext => { try { ListenerContext.Response.Close(); } catch { } }; Action <HttpSession> Purify = StoppingSession => { SessionSets.DoAction ( ss => { if (ss.Sessions.Contains(StoppingSession)) { ss.Sessions.Remove(StoppingSession); var IpAddress = StoppingSession.RemoteEndPoint.Address; var isi = ss.IpSessions[IpAddress]; if (isi.Authenticated.Contains(StoppingSession)) { isi.Authenticated.Remove(StoppingSession); } isi.Count -= 1; if (isi.Count == 0) { ss.IpSessions.Remove(IpAddress); } var SessionId = ss.SessionToId[StoppingSession]; ss.SessionIdToSession.Remove(SessionId); ss.SessionToId.Remove(StoppingSession); } } ); StoppingSession.Dispose(); }; Action <HttpListenerContext> Accept = a => { IPEndPoint e = null; try { e = (IPEndPoint)a.Request.RemoteEndPoint; var XForwardedFor = a.Request.Headers["X-Forwarded-For"]; var Address = e.Address; if ((XForwardedFor != null) && (XForwardedFor != "")) { try { IPAddress addr; if (IPAddress.TryParse(XForwardedFor.Split(',')[0].Trim(' '), out addr)) { Address = addr; } } catch { } } var XForwardedPort = a.Request.Headers["X-Forwarded-Port"]; var Port = e.Port; if ((XForwardedPort != null) && (XForwardedPort != "")) { try { int p; if (int.TryParse(XForwardedPort.Split(',')[0].Trim(' '), out p)) { Port = p; } } catch { } } e = new IPEndPoint(Address, Port); if (ServerContext.EnableLogSystem) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = "", RemoteEndPoint = e, Time = DateTime.UtcNow, Type = "Sys", Name = "RequestIn", Message = "" }); } if (a.Request.ContentLength64 < 0) { a.Response.StatusCode = 411; NotifyListenerContextQuit(a); return; } if (a.Request.ContentLength64 > ReadBufferSize) { a.Response.StatusCode = 413; NotifyListenerContextQuit(a); return; } if (!IsMatchBindingName(a.Request.Url)) { a.Response.StatusCode = 404; NotifyListenerContextQuit(a); return; } var Headers = a.Request.Headers.AllKeys.ToDictionary(k => k, k => a.Request.Headers[k]); if (Headers.ContainsKey("Range")) { a.Response.StatusCode = 400; NotifyListenerContextQuit(a); return; } if (Headers.ContainsKey("Accept-Charset")) { var AcceptCharsetParts = Headers["Accept-Charset"].Split(';'); if (AcceptCharsetParts.Length == 0) { a.Response.StatusCode = 400; NotifyListenerContextQuit(a); return; } var EncodingNames = AcceptCharsetParts[0].Split(',').Select(n => n.Trim(' ')).ToArray(); if (!(EncodingNames.Contains("utf-8", StringComparer.OrdinalIgnoreCase) || EncodingNames.Contains("*", StringComparer.OrdinalIgnoreCase))) { a.Response.StatusCode = 400; NotifyListenerContextQuit(a); return; } } { var Query = HttpListenerRequestExtension.GetQuery(a.Request); if (Query.ContainsKey("sessionid")) { HttpSession s = null; var SessionId = Query["sessionid"]; var Close = false; SessionSets.DoAction ( ss => { if (!ss.SessionIdToSession.ContainsKey(SessionId)) { a.Response.StatusCode = 403; Close = true; return; } var CurrentSession = ss.SessionIdToSession[SessionId]; if (!CurrentSession.RemoteEndPoint.Address.Equals(e.Address)) { a.Response.StatusCode = 403; Close = true; return; } s = ss.SessionIdToSession[SessionId]; } ); if (Close) { NotifyListenerContextQuit(a); return; } var NewSessionId = Convert.ToBase64String(Cryptography.CreateRandom(64)); SessionSets.DoAction ( ss => { ss.SessionIdToSession.Remove(SessionId); ss.SessionIdToSession.Add(NewSessionId, s); ss.SessionToId[s] = NewSessionId; } ); if (!s.Push(a, NewSessionId)) { NotifyListenerContextQuit(a); return; } return; } } if (MaxConnectionsValue.HasValue && (SessionSets.Check(ss => ss.Sessions.Count) >= MaxConnectionsValue.Value)) { ContextPurifyConsumer.DoOne(); PurifyConsumer.DoOne(); } if (MaxConnectionsValue.HasValue && (SessionSets.Check(ss => ss.Sessions.Count) >= MaxConnectionsValue.Value)) { a.Response.StatusCode = 503; NotifyListenerContextQuit(a); return; } if (MaxConnectionsPerIPValue.HasValue && (SessionSets.Check(ss => ss.IpSessions.ContainsKey(e.Address) ? ss.IpSessions[e.Address].Count : 0) >= MaxConnectionsPerIPValue.Value)) { a.Response.StatusCode = 503; NotifyListenerContextQuit(a); return; } if (MaxUnauthenticatedPerIPValue.HasValue && (SessionSets.Check(ss => ss.IpSessions.ContainsKey(e.Address) ? (ss.IpSessions[e.Address].Count - ss.IpSessions[e.Address].Authenticated.Count) : 0) >= MaxUnauthenticatedPerIPValue.Value)) { a.Response.StatusCode = 503; NotifyListenerContextQuit(a); return; } { var s = new HttpSession(this, e, VirtualTransportServerFactory, QueueUserWorkItem); var SessionId = Convert.ToBase64String(Cryptography.CreateRandom(64)); SessionSets.DoAction ( ss => { ss.Sessions.Add(s); if (ss.IpSessions.ContainsKey(e.Address)) { ss.IpSessions[e.Address].Count += 1; } else { var isi = new IpSessionInfo(); isi.Count += 1; ss.IpSessions.Add(e.Address, isi); } ss.SessionIdToSession.Add(SessionId, s); ss.SessionToId.Add(s, SessionId); } ); s.Start(); if (!s.Push(a, SessionId)) { NotifyListenerContextQuit(a); return; } } } catch (Exception ex) { if (ServerContext.EnableLogSystem) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = "", RemoteEndPoint = e ?? new IPEndPoint(IPAddress.Any, 0), Time = DateTime.UtcNow, Type = "Sys", Name = "Exception", Message = ExceptionInfo.GetExceptionInfo(ex) }); } try { a.Response.StatusCode = 500; } catch { } NotifyListenerContextQuit(a); } }; AcceptConsumer = new AsyncConsumer <HttpListenerContext>(QueueUserWorkItem, a => { Accept(a); return(true); }, int.MaxValue); ContextPurifyConsumer = new AsyncConsumer <HttpListenerContext>(QueueUserWorkItem, l => { PurifyContext(l); return(true); }, int.MaxValue); PurifyConsumer = new AsyncConsumer <HttpSession>(PurifierQueueUserWorkItem, s => { Purify(s); return(true); }, int.MaxValue); if (UnauthenticatedSessionIdleTimeoutValue.HasValue || SessionIdleTimeoutValue.HasValue) { var TimePeriod = TimeSpan.FromSeconds(Math.Max(TimeoutCheckPeriodValue, 1)); LastActiveTimeCheckTimer = new Timer(state => { if (UnauthenticatedSessionIdleTimeoutValue.HasValue) { var CheckTime = DateTime.UtcNow.AddIntSeconds(-UnauthenticatedSessionIdleTimeoutValue.Value); SessionSets.DoAction ( ss => { foreach (var s in ss.Sessions) { var IpAddress = s.RemoteEndPoint.Address; var isi = ss.IpSessions[IpAddress]; if (!isi.Authenticated.Contains(s)) { if (s.LastActiveTime < CheckTime) { PurifyConsumer.Push(s); } } } } ); } if (SessionIdleTimeoutValue.HasValue) { var CheckTime = DateTime.UtcNow.AddIntSeconds(-SessionIdleTimeoutValue.Value); SessionSets.DoAction ( ss => { foreach (var s in ss.Sessions) { var IpAddress = s.RemoteEndPoint.Address; var isi = ss.IpSessions[IpAddress]; if (isi.Authenticated.Contains(s)) { if (s.LastActiveTime < CheckTime) { PurifyConsumer.Push(s); } } } } ); } }, null, TimePeriod, TimePeriod); } try { Listener.Start(); } catch (HttpListenerException ex) { String Message; if (ex.ErrorCode == 5) { var l = new List <String>(); l.Add("Under Windows, try run the following as administrator:"); var UserDomainName = Environment.UserDomainName; var UserName = Environment.UserName; foreach (var p in BindingsValue) { l.Add(@"netsh http add urlacl url={0} user={1}\{2}".Formats(p, UserDomainName, UserName)); } l.Add("and delete it when you don't need it:"); foreach (var p in BindingsValue) { l.Add(@"netsh http delete urlacl url={0}".Formats(p)); } Message = String.Join("\r\n", l.ToArray()); } else { Message = ExceptionInfo.GetExceptionInfo(ex); } throw new AggregateException(Message, ex); } Action Listen = () => { if (ListeningTaskToken.IsCancellationRequested) { return; } var l = Listener; var lc = ListenConsumer; l.BeginGetContext(ar => { if (!l.IsListening) { return; } try { var a = l.EndGetContext(ar); AcceptConsumer.Push(a); } catch (HttpListenerException) { } catch (ObjectDisposedException) { } lc.Push(0); }, null); }; ListenConsumer = new AsyncConsumer <int>(QueueUserWorkItem, i => { Listen(); return(true); }, 1); Listen(); Success = true; return(true); } ); } finally { if (!Success) { Stop(); } } }