wasSharpNET – Rev 19

Subversion Repositories:
Rev:
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;

namespace wasSharpNET.Network.HTTP
{
    public abstract class HTTPServer : IDisposable
    {
        private int activeRequests;

        private HttpListener HTTPListener = null;

        private int processedRequests;

        public AuthenticationSchemes AuthenticationSchemes { get; set; } =
            AuthenticationSchemes.None;

        public bool IsRunning => HTTPListener != null && HTTPListener.IsListening;

        public bool Start(IEnumerable<string> prefixes)
        {
            HTTPListener = new HttpListener()
            {
                AuthenticationSchemes = AuthenticationSchemes
            };

            // Add all prefixes.
            HTTPListener.Prefixes.Clear();
            foreach (var prefix in prefixes)
            {
                HTTPListener.Prefixes.Add(prefix);
            }

            // Do not bomb if the client disconnects.
            HTTPListener.IgnoreWriteExceptions = true;
            HTTPListener.Start();
            ThreadPool.QueueUserWorkItem(Listen, new HTTPServerCallbackState(HTTPListener));
            return true;
        }

        public void Stop()
        {
            HTTPListener.Stop();
        }

        private void Listen(object state)
        {
            var callbackState = (HTTPServerCallbackState)state;

            while (callbackState.Listener.IsListening)
            {
                callbackState.Listener.BeginGetContext(ContextCallback, callbackState);
                callbackState.ContextRetrieved.WaitOne();
            }
        }

        public abstract void ProcessHTTPContext(HttpListenerContext context);

        private void ContextCallback(IAsyncResult ar)
        {
            var callbackState = (HTTPServerCallbackState)ar.AsyncState;
            HttpListenerContext httpContext = null;

            Interlocked.Increment(ref processedRequests);
            Interlocked.Increment(ref activeRequests);

            try
            {
                httpContext = callbackState.Listener.EndGetContext(ar);
            }
            catch (Exception)
            {
                Interlocked.Decrement(ref activeRequests);
                return;
            }
            finally
            {
                callbackState.ContextRetrieved.Set();
            }

            if (httpContext == null)
                return;

            try
            {
                ProcessHTTPContext(httpContext);
            }
            finally
            {
                Interlocked.Decrement(ref activeRequests);
            }
        }

        public void Dispose()
        {
            Stop();
            HTTPListener = null;
        }

        private class HTTPServerCallbackState
        {
            public HTTPServerCallbackState(HttpListener listener)
            {
                if (listener == null)
                    throw new ArgumentNullException("listener");
                Listener = listener;
                ContextRetrieved = new AutoResetEvent(false);
            }

            public HttpListener Listener { get; }

            public AutoResetEvent ContextRetrieved { get; }
        }
    }
}