csharp/0ffffffffh/sozluk-cgi-revival/sozluk_backend/Core/Edi/EdisFace.cs

EdisFace.cs
using sozluk_backend.Core.Cache;
using sozluk_backend.Core.Sys;
using sozluk_backend.Core.Sys.DataStore;
using sozluk_backend.Core.Sys.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;

namespace sozluk_backend.Core.Edi
{
    clast EdisFace
    {
        AsyncCallback handlerCallback;
        int port;
        HttpListener httpListener;
        string cachedIndexHtml;
        object lck = new object();

        private Dictionary BuildForm(HttpListenerContext ctx)
        {
            string[] items;

            string post;

            using (StreamReader sr = new StreamReader(ctx.Request.InputStream))
            {
                post = sr.ReadToEnd();
            }

            if (string.IsNullOrEmpty(post))
                return null;

            items = post.Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);

            var dict = new Dictionary();

            foreach (var item in items)
            {
                string[] kv = item.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);

                if (kv.Length == 2)
                {
                    kv[1] = System.Web.HttpUtility.UrlDecode(kv[1],Encoding.GetEncoding("iso-8859-9"));


                    dict.Add(kv[0], kv[1]);
                }

            }

            return dict;
        }

        private string MimeTypeFromExt(string ext)
        {
            switch (ext)
            {
                case ".gif":
                    return "image/gif";
                case ".html":
                    return "text/html";
            }

            return "text/plain";
        }

        private bool ReplyWithFile(HttpListenerContext ctx, string fileName)
        {
            Stream fs;

            if (!File.Exists(fileName))
                return false;

            try
            {
                fs = File.OpenRead(fileName);
            }
            catch(Exception e)
            {
                Log.Error("{0} - {1}", fileName, e.Message);
                return false;
            }

            ctx.Response.ContentLength64 = fs.Length;
            ctx.Response.StatusCode = 200;

            ctx.Response.ContentEncoding = Encoding.ASCII;
            ctx.Response.ContentType = MimeTypeFromExt(Path.GetExtension(fileName));

            fs.CopyTo(ctx.Response.OutputStream);

            fs.Close();
            fs.Dispose();

            return true;
        }

        private bool ReplyIndex(HttpListenerContext ctx, string statusMessage)
        {
            string content = cachedIndexHtml.Replace("%%STATUS_MESSAGE%%", statusMessage);

            byte[] data = Encoding.ASCII.GetBytes(content);

            try
            {
                ctx.Response.ContentLength64 = data.Length;
                ctx.Response.StatusCode = 200;

                ctx.Response.ContentEncoding = Encoding.ASCII;
                ctx.Response.ContentType = "text/html";
                ctx.Response.OutputStream.Write(data, 0, data.Length);
            }
            catch (Exception e)
            {
                Log.Error(e.Message);
                data = null;
                return false;
            }

            data = null;
            return true;
        }

        private void CacheDeniedClient(string clientIp)
        {
            string key = Edi.MakeUniqueCacheKey("EDI_DENYLIST");

            HashSet denyHashlist = null;

            lock (lck)
            {
                if (!CacheManager.TryGetCachedResult(
                    key,
                    out denyHashlist)
                    )
                {
                    denyHashlist = new HashSet();
                }


                if (!denyHashlist.Contains(clientIp))
                {
                    denyHashlist.Add(clientIp);
                    CacheManager.CacheObject(key, denyHashlist,TimeSpan.FromHours(3));
                }
            }

            denyHashlist.Clear();
            denyHashlist = null;
        }

        private bool IsClientDeniedAtThisSessionBefore(string clientIp)
        {
            bool denied = false;
            string key = Edi.MakeUniqueCacheKey("EDI_DENYLIST");

            HashSet denyHashlist = null;

            lock (lck)
            {
                if (!CacheManager.TryGetCachedResult(
                    key,
                    out denyHashlist)
                    )
                {
                    return false;
                }
            }

            denied = denyHashlist.Contains(clientIp);

            denyHashlist.Clear();
            denyHashlist = null;

            return denied;
        }

        private bool IsClientPermittedForSuserAddition(HttpListenerContext ctx, bool modify)
        {
            bool allowed;
            string clientIp;
            string query;
            

            clientIp = ctx.Request.RemoteEndPoint.Address.MapToIPv4().ToString();

            if (IsClientDeniedAtThisSessionBefore(clientIp))
            {
                return false;
            }

            SqlServerIo sql = SqlServerIo.Create();

            if (!sql.Ready)
                return false;

            query = "DECLARE @Permit BIT " +
                "EXEC IsRegistrationAllowed {0}, '{1}', @Permit OUTPUT " +
                "SELECT @Permit AS IsAllowed";
            
            
            sql.Execute(false, query, modify?1:0,clientIp);

            sql.Read();

            allowed = sql.GetValueOfColumn("IsAllowed");
            
            SqlServerIo.Release(sql);

            if (!allowed)
                CacheDeniedClient(clientIp);

            return allowed;
        }

        private void HandleAddSuser(HttpListenerContext ctx, string suserName, string pwd)
        {
            string replyText;


            if (!IsClientPermittedForSuserAddition(ctx,false))
            {
                Log.Warning("Too much user registration attempt on the same connection.");

                ReplyIndex(ctx, 
                    "oooooh ma$allah. aile epey geni$ sizde. dede, amca, torun torba iyidir in$allah." +
                    "ancak sorun $u ki, ayni baglanti uzerinden gunde en fazla 3 kayit yapabiliyorsunuz." +
                    "eksi sozluk'u bu kadar sevdiginizi bilmiyordum. gozlerim ya$ardi." +
                    "eh napalim, ailenin kalan bireylerini yarin kaydetmeyi dene.");
                return;
            }

            EdisHand.AddSuserResult result = EdisHand.AddSuser(suserName, pwd);

            Log.Info("Suser registration result for {0}, {1}", suserName, result.ToString());


            if (result == EdisHand.AddSuserResult.Joined)
            {
                IsClientPermittedForSuserAddition(ctx, true);

                ReplyIndex(ctx, 
                    suserName + 
                    " ast super bir nick secimi. muthi$ hatta o kadar begendim ki dayanamadim kaydediverdim. tebrik ediyorum seni.");

                return;
            }

            replyText = "olmadi. olamadi... cunku ";


            switch (result)
            {
                case EdisHand.AddSuserResult.HasNotAllowedChar:
                    replyText += "alt cizgi, tire, turkce karakter falan filan bunlar ast cirkin $eyler. ";
                    break;
                case EdisHand.AddSuserResult.TakenBefore:
                    replyText += "ast $anssizsin, senden once kapilmi$ bu nick. bugun evden di$ari cikma bence";
                    break;
                case EdisHand.AddSuserResult.TooLongOrShort:
                    replyText += "nick uzunlugunu gozden gecir bence";
                    break;
                case EdisHand.AddSuserResult.BadLuck:
                    replyText += "kotu $ans, tekrar deneyebilirsin. yuz yilda bir olacak $ey geldi seni buldu iyi mi?";
                    break;
            }

            ReplyIndex(ctx, replyText);

        }

        private void HandlePost(HttpListenerContext ctx, Dictionary postForm)
        {
            if (postForm == null)
            {
                return;
            }

            if (postForm.ContainsKey("nick") && postForm.ContainsKey("pwd"))
            {
                HandleAddSuser(ctx, postForm["nick"], postForm["pwd"]);
            }
            else
            {
                ReplyIndex(ctx, "gerekli bir $eyler unuttun.");
            }
        }
        
        private void RequestHandler(IAsyncResult result)
        {
            Dictionary form;

            string objectName,path;
            HttpListenerContext ctx;

            if (!this.httpListener.IsListening)
                return;

            try
            {
                ctx = this.httpListener.EndGetContext(result);
            }
            catch (Exception e)
            {
                Log.Error("request completion error: " + e.Message);
                RegisterRequestWaiter(null);
                return;
            }

            form = BuildForm(ctx);

            objectName = ctx.Request.Url.LocalPath;

            var ext = Path.GetExtension(objectName);
            objectName = Path.GetFileNameWithoutExtension(objectName);

            objectName = objectName.
                Replace(".", "").
                Replace("/","").
                Replace("\\","");

            if (string.IsNullOrEmpty(objectName))
                objectName = "\\";
            else
                objectName = "\\" + objectName + ext;

            path = Config.Get().HtmlContentRoot + objectName;
            
            RegisterRequestWaiter(null);

            if (objectName == "\\")
            {
                if (ctx.Request.HttpMethod.ToLower() == "post")
                {
                    HandlePost(ctx, form);
                }
                else
                    ReplyIndex(ctx, string.Empty);
            }
            else
            {
                ReplyWithFile(ctx, path);
            }
            
            ctx.Response.Close();
        }

        private void RegisterRequestWaiter(object state)
        {
            try
            {
                this.httpListener.BeginGetContext(this.handlerCallback, state);
            }
            catch (Exception e)
            {
                Log.Error(e.Message);
            }
        }

        public bool WipeClientInfos()
        {
            CacheManager.Remove(Edi.MakeUniqueCacheKey("EDI_DENYLIST"));

            SqlServerIo sql = SqlServerIo.Create();

            if (!sql.Ready)
                return false;

            if (!sql.Execute(true, "DELETE FROM ClientState;"))
            {
                SqlServerIo.Release(sql);
                return false;
            }

            SqlServerIo.Release(sql);
            return true;
        }

        public EdisFace(int port)
        {
            this.port = port;
            this.handlerCallback = new AsyncCallback(RequestHandler);

#if DEBUG
            WipeClientInfos();
#endif
            this.httpListener = new HttpListener();
            this.httpListener.Prefixes.Add(string.Format("http://localhost:{0}/", port));
            this.httpListener.Prefixes.Add(string.Format("http://sourtimes.oguzkartal.net:{0}/", port));

            this.httpListener.Start();

            cachedIndexHtml = File.ReadAllText(Config.Get().HtmlContentRoot + "\\edi.html");

            if (this.httpListener.IsListening)
                RegisterRequestWaiter(null);
            else
                Log.Warning("edi service could not be started");

        }

        public void Close()
        {
            this.httpListener.Stop();
            this.httpListener.Close();
        }

        public bool IsAlive
        {
            get { return this.httpListener.IsListening; }
        }
    }
}