using System; using System.Collections.Generic; using ln.http.resources.session; using ln.logging; using ln.types.threads; using ln.types; using ln.http.listener; using ln.http.connections; using ln.types.net; using ln.http.cert; using System.Globalization; using System.Net.Sockets; namespace ln.http { public class HTTPServer { public static int backlog = 5; public static int defaultPort = 8080; public static bool exclusivePortListener = false; public HttpApplication DefaultApplication { get; set; } public SessionCache SessionCache { get; set; } public bool IsRunning => !shutdown && (threadPool.CurrentPoolSize > 0); public Func CreateServerConnection { get; set; } public Logger Logger { get; set; } bool shutdown = false; List listeners = new List(); public Listener[] Listeners => listeners.ToArray(); Dictionary applications = new Dictionary(); DynamicPool threadPool; public DynamicPool ThreadPool => threadPool; public HTTPServer() { Logger = Logger.Default; SessionCache = new SessionCache(); threadPool = new DynamicPool(1024); } public void AddListener(Listener listener) { listeners.Add(listener); if (IsRunning) StartListener(listener); } public void StartListener(Listener listener) { listener.Open(); threadPool.Enqueue( () => listener.AcceptMany( (connection) => threadPool.Enqueue( () => this.HandleConnection(connection) ) ) ); } public void StopListener(Listener listener) { listener.Close(); } public void AddEndpoint(Endpoint endpoint) { AddListener(new HttpListener(endpoint)); } public void AddApplication(URI BaseURI, HttpApplication application) { applications[BaseURI] = application; } public HttpApplication GetHttpApplication(URI baseURI) { HttpApplication application = DefaultApplication; if (applications.ContainsKey(baseURI)) application = applications[baseURI]; return application; } public void Start() { threadPool.Start(); foreach (Listener listener in listeners) StartListener(listener); } public void Stop() { lock (this) { this.shutdown = true; } foreach (Listener listener in listeners) StopListener(listener); threadPool.Stop(true); } private void HandleConnection(Connection connection) { HttpRequest httpRequest = null; bool keepAlive = true; try { do { httpRequest = connection.ReadRequest(this); if (httpRequest == null) break; httpRequest.ApplySession(SessionCache); HttpApplication application = GetHttpApplication(new URI(httpRequest.BaseURI.ToString())); application.Authenticate(httpRequest); application.Authorize(httpRequest); HttpResponse response = application.GetResponse(httpRequest); keepAlive = httpRequest.GetRequestHeader("connection","keep-alive").Equals("keep-alive") && response.GetHeader("connection", "keep-alive").Equals("keep-alive"); response.SetHeader("connection", keepAlive ? "keep-alive" : "close"); connection.SendResponse(response); } while (keepAlive); } catch (Exception e) { Logging.Log(e); if (httpRequest != null) { HttpResponse httpResponse = new HttpResponse(httpRequest); httpResponse.StatusCode = 500; httpResponse.ContentWriter.WriteLine("500 Internal Server Error"); connection.SendResponse(httpResponse); } } connection.GetStream().Close(); } public void Log(DateTime startTime,double duration,HttpRequest httpRequest,HttpResponse httpResponse) { Logger.Log(LogLevel.INFO, "{0} {1} {2} {3}",startTime.ToString("yyyyMMdd-HH:mm:ss"),duration.ToString(CultureInfo.InvariantCulture),httpRequest.Hostname,httpRequest.RequestURL); } } }