using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
public class HttpServer : IDisposable
{
    private const string NotFoundResponse = "<!doctype html><html><body>Resource not found</body></html>";
    private readonly HttpListener httpListener;
    private readonly CancellationTokenSource cts = new CancellationTokenSource();
    private readonly string prefixPath;

    private Task processingTask;

    public HttpServer(string listenerUriPrefix)
    {
        this.prefixPath = ParsePrefixPath(listenerUriPrefix);
        this.httpListener = new HttpListener();
        this.httpListener.Prefixes.Add(listenerUriPrefix);
    }

    private static string ParsePrefixPath(string listenerUriPrefix)
    {
        var match = Regex.Match(listenerUriPrefix, @"http://(?:[^/]*)(?:\:\d+)?/(.*)");
        if (match.Success)
        {
            ].Value.ToLowerInvariant();
        }
        else
        {
            return string.Empty;
        }
    }

    public void Start()
    {
        this.httpListener.Start();
        this.processingTask = Task.Factory.StartNew(async () => await ProcessRequests(), TaskCreationOptions.LongRunning);
    }

    private async Task ProcessRequests()
    {
        while (!this.cts.IsCancellationRequested)
        {
            try
            {
                var context = await this.httpListener.GetContextAsync();
                try
                {
                    await ProcessRequest(context).ConfigureAwait(false);
                    context.Response.Close();
                }
                catch (Exception ex)
                {
                    context.Response.StatusCode = ;
                    context.Response.StatusDescription = "Internal Server Error";
                    context.Response.Close();
                    Console.WriteLine("Error processing HTTP request\n{0}", ex);
                }
            }
            catch (ObjectDisposedException ex)
            {
                if ((ex.ObjectName == this.httpListener.GetType().FullName) && (this.httpListener.IsListening == false))
                {
                    return; // listener is closed/disposed
                }
                Console.WriteLine("Error processing HTTP request\n{0}", ex);
            }
            catch (Exception ex)
            {
                HttpListenerException httpException = ex as HttpListenerException;
                )// IO operation aborted
                {
                    Console.WriteLine("Error processing HTTP request\n{0}", ex);
                }
            }
        }
    }

    private Task ProcessRequest(HttpListenerContext context)
    {
        if (context.Request.HttpMethod.ToUpperInvariant() != "GET")
        {
            return WriteNotFound(context);
        }

        var urlPath = context.Request.RawUrl.Substring(this.prefixPath.Length)
            .ToLowerInvariant();

        switch (urlPath)
        {
            case "/":
                if (!context.Request.Url.ToString().EndsWith("/"))
                {
                    context.Response.Redirect(context.Request.Url + "/");
                    context.Response.Close();
                    );
                }
                else
                {
                    return WriteString(context, "Hello World!", "text/plain");
                }
            case "/favicon.ico":
                return WriteFavIcon(context);
            case "/ping":
                return WritePong(context);
        }
        return WriteNotFound(context);
    }

    private static Task WritePong(HttpListenerContext context)
    {
        return WriteString(context, "pong", "text/plain");
    }

    private static async Task WriteFavIcon(HttpListenerContext context)
    {
        context.Response.ContentType = "image/png";
        context.Response.StatusCode = ;
        context.Response.StatusDescription = "OK";
        using (var stream = File.Open("icon.png", FileMode.Open))
        {
            var output = context.Response.OutputStream;
            await stream.CopyToAsync(output);
        }
    }

    private static Task WriteNotFound(HttpListenerContext context)
    {
        , "NOT FOUND");
    }

    private static async Task WriteString(HttpListenerContext context, string data, string contentType,
        , string httpStatusDescription = "OK")
    {
        AddCORSHeaders(context.Response);
        AddNoCacheHeaders(context.Response);

        context.Response.ContentType = contentType;
        context.Response.StatusCode = httpStatus;
        context.Response.StatusDescription = httpStatusDescription;

        var acceptsGzip = AcceptsGzip(context.Request);
        if (!acceptsGzip)
        {
            , true))
            {
                await writer.WriteAsync(data).ConfigureAwait(false);
            }
        }
        else
        {
            context.Response.AddHeader("Content-Encoding", "gzip");
            using (GZipStream gzip = new GZipStream(context.Response.OutputStream, CompressionMode.Compress, true))
            , true))
            {
                await writer.WriteAsync(data).ConfigureAwait(false);
            }
        }
    }

    private static bool AcceptsGzip(HttpListenerRequest request)
    {
        string encoding = request.Headers["Accept-Encoding"];
        if (string.IsNullOrEmpty(encoding))
        {
            return false;
        }

        return encoding.Contains("gzip");
    }

    private static void AddNoCacheHeaders(HttpListenerResponse response)
    {
        response.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate");
        response.Headers.Add("Pragma", "no-cache");
        response.Headers.Add(");
    }

    private static void AddCORSHeaders(HttpListenerResponse response)
    {
        response.Headers.Add("Access-Control-Allow-Origin", "*");
        response.Headers.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    }

    private void Stop()
    {
        cts.Cancel();
        if (processingTask != null && !processingTask.IsCompleted)
        {
            processingTask.Wait();
        }
        if (this.httpListener.IsListening)
        {
            this.httpListener.Stop();
            this.httpListener.Prefixes.Clear();
        }
    }

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

利用HttpListener创建简单的HTTP服务的更多相关文章

  1. 通过HttpListener实现简单的Http服务

    使用HttpListener实现简单的Http服务 HttpListener提供一个简单的.可通过编程方式控制的 HTTP 协议侦听器.使用它可以很容易的提供一些Http服务,而无需启动IIS这类大型 ...

  2. 利用WCF创建简单的RESTFul Service

    1):用VS2013创建一个WCF的工程,如下图所示: 2):我们来看一下默认状态下的config文件内容,这里的内容我们会再后续的步骤中进行修改 <?xml version="1.0 ...

  3. 使用C#创建简单的WCF服务

    一.开发环境 操作系统:Windows 10 开发环境:VS2015 编程语言:C# IIS版本:10.0.0.0 二.添加WCF服务.Internet Information Services(II ...

  4. 通过VS创建简单的WCF服务

    http://www.cnblogs.com/artech/archive/2007/09/15/893838.html http://www.topwcftutorials.net/2013/09/ ...

  5. 使用Topshelf组件构建简单的Windows服务

    很多时候都在讨论是否需要了解一个组件或者一个语言的底层原理这个问题,其实我个人觉得,对于这个问题,每个人都有自己的看法,个人情况不同,选择的方式也就会不同了.我个人觉得无论学习什么,都应该尝试着去了解 ...

  6. 利用navicat创建存储过程、触发器和使用游标的简单实例

    利用navicat创建存储过程.触发器和使用游标的简单实例 标签: navicat存储过程触发器mysql游标 2013-08-03 21:34 15516人阅读 评论(1) 收藏 举报  分类: 数 ...

  7. 利用OpenShift托管Node.js Web服务进行微信公众号开发

    最近写了一个微信的翻译机器人.用户只要关注该公众号,发送英文的消息,就能收到中文翻译的回复.有兴趣的读者可以扫描下面的二维码关注该公众号,尝试发送英文单词试试看.(有时候第一次发送单词会收到“该公众号 ...

  8. 利用Oracle创建数据库

    本文仅用于学习交流,商业用途请支持正版!转载请注明:http://www.cnblogs.com/mxbs/p/6217151.html 数据库的创建 打开"所有程序"-" ...

  9. Web Service 的创建简单编码、发布和部署

    最近,老大准备将已有的C/S架构项目中的通信部分做成通用,需要将其支持WebService为以后项目向着B/S架构升级做好铺垫,为此身为屌丝的我去各种百度WebService是个什么卵玩意,然后逐渐搭 ...

随机推荐

  1. jQuery的DOM操作详解

    DOM(Document Object Model-文档对象模型):一种与浏览器, 平台, 语言无关的规则, 使用该接口可以轻松地访问页面中所有的标准组件DOM操作的分类 核心-DOM: DOM Co ...

  2. HDU 2045 不容易系列之(3)―― LELE的RPG难题(递推)

    题意:有排成一行的n个方格,用红(Red).粉(Pink).绿(Green)三色涂每个格子,每格涂一色,要求任何相邻的方格不能同色,且首尾两格也不同色.求全部的满足要求的涂法. 题解:本来当n=1时, ...

  3. SQLServer存储过程和触发器学习记录及简单例子

     一.存储过程 存储过程即为能完成特定功能的一组SQL语句集.如果需要对查出的多条数据进行操作的话,这里需要理解游标(CURSOR)的概念,对于oracle有for each row命令,可以不用游标 ...

  4. python包下载地址

    https://pypi.python.org/pypi http://www.lfd.uci.edu/~gohlke/pythonlibs/ 当在线安装安装不了时,需要将安装包下载到本地,进行本地p ...

  5. ELb表达式

    主要用于servlet的4个作用域取值:pageScope.requestScope.sessionScope.applicationScope 取值顺序依次从小到大.取值方式如:操作javabean ...

  6. C#版的eval,C#Light开源嵌入式脚本,unity热更新不再愁

    目前最新版本AlphaV0.06 完全的c#语法,可用于一切能运行C#的场合,wp windows xamarin mono asp.net unity3d 内嵌了int uint bool stri ...

  7. webservice MaxReceivedMessageSize :已超过传入消息(65536)的最大消息大小配额

    在客户端的webconfig文件的webservice节点进行如下配置:(注:此处客户端为应用程序的config文件) <system.serviceModel> <bindings ...

  8. 小白死去活来的安装ros_qtc_plugin

    在距离写上一篇有关ROS的文章已经过去了很久了.在这段时间内一直在积累,盼望着能够厚积薄发,但还是被无情的社会折磨的死去活来,深深的体会到了一般学校和重点学校找工作的差别,以及用人单位的区别对待.说到 ...

  9. Servlet域对象ServletContext小应用------计算网站访问量

    package cn.yzu; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Servlet ...

  10. 我的android学习经历31

    最近把四大组件,网络编程,以及一些常用的控件都学完了,不过感觉还不是特别牢固,所以决定再花一点时间重新过一遍,你们有这样的感觉吗?