using System; using System.Net.Sockets; using Mozi.HttpEmbedded.Auth; using Mozi.HttpEmbedded.Cert; using Mozi.HttpEmbedded.Common; using Mozi.HttpEmbedded.Compress; using Mozi.HttpEmbedded.Docment; using Mozi.HttpEmbedded.Page; using Mozi.HttpEmbedded.Source; namespace Mozi.HttpEmbedded { //TODO 2020/09/19 增加WebService功能 //TODO 2020/09/28 增加信号量机制 //TODO 2021/05/05 实现HTTPS功能 //TODO 2021/05/05 实现管道机制pipelining 即同一TCP链接允许发起多个HTTP请求 HTTP/1.1 //TODO 2021/05/07 增加分块传输 chunked /// /// Http服务器 /// public class HttpServer { private readonly SocketServer _sc=new SocketServer(); private WebDav.DavServer _davserver; private int _port=80; private int _iporthttps = 443; private long _maxFileSize = 10 * 1024 * 1024; private long _maxRequestSize = 10 * 1024 * 1024; private string _tempPath = ""; private string _serverName = "HttpEmbedded"; private string _indexPageMatchPattern = "index.html,index.htm"; //允许和公开的方法 private RequestMethod[] MethodAllow = new RequestMethod[] { RequestMethod.OPTIONS, RequestMethod.TRACE, RequestMethod.GET, RequestMethod.HEAD, RequestMethod.POST, RequestMethod.COPY, RequestMethod.PROPFIND, RequestMethod.LOCK, RequestMethod.UNLOCK }; private RequestMethod[] MethodPublic = new RequestMethod[] { RequestMethod.OPTIONS, RequestMethod.GET, RequestMethod.HEAD, RequestMethod.PROPFIND, RequestMethod.PROPPATCH, RequestMethod.MKCOL, RequestMethod.PUT, RequestMethod.DELETE, RequestMethod.COPY, RequestMethod.MOVE, RequestMethod.LOCK, RequestMethod.UNLOCK }; //证书管理器 private CertManager _certMg; //HTTPS开启标识 private bool _httpsEnabled = false; /// /// 支持的HTTP服务协议版本 /// public HttpVersion ProtocolVersion { get; set; } /// /// 是否使用基本认证 /// public bool EnableAuth { get; private set; } /// /// 认证器 /// private Authenticator Auth { get; set; } /// /// 是否启用访问控制 IP策略 /// public bool EnableAccessControl { get; private set; } /// /// 是否开启压缩 /// public bool EnableCompress { get; private set; } /// /// 压缩选项 /// public CompressOption ZipOption { get; private set; } /// /// 最大接收文件大小 默认10Mb /// public long MaxFileSize { get { return _maxFileSize; } private set { _maxFileSize = value; } } public long MaxRequestSize { get { return _maxRequestSize; } private set { _maxRequestSize = value; } } /// /// 服务端口 /// public int Port { get { return _port; } private set { _port = value; } } /// /// HTTPS服务端口 /// internal int PortHTTPS { get { return _iporthttps; } private set { _iporthttps = value; } } /// /// 时区 /// public string Timezone { get; set; } /// /// 编码格式 /// public string Encoding { get; set; } /// /// 是否启用WebDav /// public bool EnableWebDav { get; private set; } /// /// 服务器名称 /// public string ServerName { get { return _serverName; } private set { _serverName = value; } } /// /// 临时文件目录 /// public string TempPath { get { return _tempPath; } private set { _tempPath = value; } } public HttpServer() { //配置默认服务器名 _serverName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name+ "/" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); Auth =new Authenticator(); _sc.OnServerStart += _sc_OnServerStart; _sc.OnClientConnect += _sc_OnClientConnect; _sc.OnReceiveStart += _sc_OnReceiveStart; _sc.AfterReceiveEnd += _sc_AfterReceiveEnd; _sc.AfterServerStop += _sc_AfterServerStop; } /// /// 服务器启动事件 /// /// /// void _sc_OnReceiveStart(object sender, DataTransferArgs args) { } /// /// 服务器关闭事件 /// /// /// void _sc_AfterServerStop(object sender, ServerArgs args) { } //TODO 响应码处理有问题 /// /// 响应请求 /// /// /// void _sc_AfterReceiveEnd(object sender, DataTransferArgs args) { HttpContext context=new HttpContext(); context.Response=new HttpResponse(); StatusCode sc = StatusCode.Success; try { context.Request = HttpRequest.Parse(args.Data); //TODO HTTP/1.1 通过Connection控制连接 服务器同时对连接进行监测 保证服务器效率 //DONE 此处应判断Content-Length然后继续读流 //TODO 如何解决文件传输内存占用过大的问题 long contentLength = -1; if (context.Request.Headers.Contains(HeaderProperty.ContentLength.PropertyName)){ var propContentLength = context.Request.Headers.GetValue(HeaderProperty.ContentLength.PropertyName); contentLength = int.Parse(propContentLength); } if (contentLength == -1 || contentLength <= context.Request.Body.Length) { } else { //TODO 此处是否会形成死循环 //继续读流 args.Socket.BeginReceive(args.State.Buffer, 0, args.State.Buffer.Length, SocketFlags.None, _sc.CallbackReceive, args.State); return; } if (!EnableAuth) { sc = HandleRequest(ref context); } else { sc = HandleAuth(ref context); } } catch (Exception ex) { #region 测试片段,模板引擎开发好以后注释掉 string doc = DocLoader.Load("Error.html"); doc = doc.Replace("${Error.Code}", StatusCode.InternalServerError.Code.ToString()); doc=doc.Replace("${Error.Description}", ex.StackTrace ?? ex.StackTrace.ToString()); #endregion context.Response.Write(doc); context.Response.Headers.Add(HeaderProperty.ContentType, Mime.GetContentType("html")); sc = StatusCode.InternalServerError; Log.Error(ex.Message+":"+ex.StackTrace??""); } finally { } //最后响应数据 if (args.Socket != null && args.Socket.Connected) { context.Response.AddHeader(HeaderProperty.Server, ServerName); context.Response.SetStatus(sc); args.Socket.Send(context.Response.GetBuffer()); args.Socket.Close(100); } GC.Collect(); } /// /// 处理认证 /// /// /// private StatusCode HandleAuth(ref HttpContext context) { var authorization = context.Request.Headers.GetValue(HeaderProperty.Authorization.PropertyName); if (!string.IsNullOrEmpty(authorization) && Auth.Check(authorization)) { return HandleRequest(ref context); } else { context.Response.AddHeader(HeaderProperty.WWWAuthenticate, string.Format("{0} realm=\"{1}\"", Auth.AuthType.Name,AuthorizationType.REALM)); return StatusCode.Unauthorized; } } //TODO 2020/09/18 考虑增加断点续传的功能 //TODO 2020/09/18 增加缓存功能 //TODO 2020/09/19 增加默认页面功能 /// /// 处理请求 /// /// private StatusCode HandleRequest(ref HttpContext context) { RequestMethod method = context.Request.Method; if (method == RequestMethod.OPTIONS) { return HandleRequestOptions(ref context); } if (method == RequestMethod.GET || method == RequestMethod.POST || method == RequestMethod.HEAD||method==RequestMethod.PUT ||method == RequestMethod.DELETE||method==RequestMethod.TRACE||method==RequestMethod.CONNECT) { StaticFiles st = StaticFiles.Default; var path = context.Request.Path; string fileext = GetFileExt(path); string contenttype = Mime.GetContentType(fileext); //判断资源类型 bool isStatic = st.IsStatic(fileext); context.Response.Headers.Add(HeaderProperty.ContentType, contenttype); if (context.Request.Path == "/") { context.Response.Write(DocLoader.Load("DefaultHome.html")); context.Response.Headers.Add(HeaderProperty.ContentType, Mime.GetContentType("html")); return StatusCode.Success; } //静态文件处理 else if (st.Enabled && isStatic) { //响应静态文件 if (st.Exists(path, "")) { string ifmodifiedsince =context.Request.Headers.GetValue(HeaderProperty.IfModifiedSince.PropertyName); if (st.CheckIfModified(path, ifmodifiedsince)) { DateTime dtModified = st.GetLastModified(path).ToUniversalTime(); context.Response.Headers.Add(HeaderProperty.LastModified, dtModified.ToString("r")); context.Response.Write(st.Load(path, "")); } else { return StatusCode.NotModified; } } else { return StatusCode.NotFound; } } else { //动态页面默认ContentType为txt/plain context.Response.Headers.Add(HeaderProperty.ContentType, Mime.GetContentType("txt")); //响应动态页面 return HandleRequestRoutePages(ref context); } } //WEBDAV部分 else { return HandleRequestWebDAV(ref context); } return StatusCode.Success; } /// /// 处理METHOD-OPTIONS请求 /// /// /// private StatusCode HandleRequestOptions(ref HttpContext context) { foreach (RequestMethod verb in MethodAllow) context.Response.AddHeader("Allow", verb.Name); foreach (RequestMethod verb in MethodPublic) context.Response.AddHeader("Public", verb.Name); // Sends 200 OK return StatusCode.Success; } /// /// 处理WebDAV请求 /// private StatusCode HandleRequestWebDAV(ref HttpContext context) { RequestMethod method = context.Request.Method; if (EnableWebDav) { return _davserver.ProcessRequest(ref context); } return StatusCode.Forbidden; //RequestMethod.PROPFIND,RequestMethod.PROPPATCH RequestMethod.MKCOL RequestMethod.COPY RequestMethod.MOVE RequestMethod.LOCK RequestMethod.UNLOCK } /// /// 取URL资源扩展名 /// /// /// private string GetFileExt(string path) { string[] file = path.Split(new[] { (char)ASCIICode.QUESTION }, StringSplitOptions.RemoveEmptyEntries); string ext = ""; string purepath = file[0]; if (purepath.LastIndexOf((char)ASCIICode.DOT) >= 0) { ext = purepath.Substring(purepath.LastIndexOf((char)ASCIICode.DOT) + 1); } return ext; } /// /// 路由页面 /// /// private StatusCode HandleRequestRoutePages(ref HttpContext context) { Router router=Router.Default; if (router.Match(context.Request.Path) != null) { object result=null; result = router.Invoke(context); if (result != null) { context.Response.Write(result.ToString()); return StatusCode.Success; } else { return StatusCode.InternalServerError; } } return StatusCode.NotFound; } void _sc_OnServerStart(object sender, ServerArgs args) { //throw new NotImplementedException(); } void _sc_OnClientConnect(object sender, ClientConnectArgs args) { //throw new NotImplementedException(); } /// /// 配置服务端口 /// /// /// public HttpServer SetPort(int port) { _port = port; return this; } /// /// 启用认证 /// 此方法可连续配置用户 /// /// 访问认证类型 /// public HttpServer UseAuth(AuthorizationType at) { EnableAuth = true; Auth.SetAuthType(at); return this; } /// /// 设置服务器认证用户 /// 如果=,此设置就没有意义 /// /// /// /// public HttpServer SetUser(string userName, string userPassword) { Auth.SetUser(userName, userName); return this; } //TODO 进一步实现GZIP的控制逻辑 /// /// 启用Gzip /// /// public HttpServer UseGzip(CompressOption option) { EnableCompress = true; ZipOption = option; return this; } /// /// 允许静态文件访问 /// /// 静态文件根目录 /// public HttpServer UseStaticFiles(string root) { StaticFiles.Default.Enabled = true; StaticFiles.Default.SetRoot(root); return this; } /// /// 配置虚拟目录 /// /// /// /// public HttpServer SetVirtualDirectory(string name,string path) { if (StaticFiles.Default.Enabled) { StaticFiles.Default.SetVirtualDirectory(name, path); } return this; } /// /// 启用WebDav /// /// /// public HttpServer UseWebDav(string root) { EnableWebDav = true; //DONE WEBDAV服务初始化 if (_davserver == null) { _davserver = new WebDav.DavServer(); _davserver.SetStore(root); } return this; } //TODO 实现一个反向代理服务 /// /// 实现代理 /// /// public HttpServer UseProxy() { throw new NotImplementedException(); } /// /// /// /// /// public HttpServer UseErrorPage(string page) { throw new NotImplementedException(); } /// /// 设置临时文件目录 /// /// /// public HttpServer UseTempPath(string path) { throw new NotImplementedException(); } /// /// 设置服务器名称 /// /// /// public HttpServer SetServerName(string serverName) { _serverName = serverName; return this; } //TODO HTTPS internal HttpServer UseHttps() { _httpsEnabled = true; throw new NotImplementedException(); } /// /// 配置安全证书 /// /// 证书类型为x509 /// /// /// /// 证书必须为X509 *.pfx /// /// 证书密码 /// public HttpServer SetCertification(string filePath,string password) { throw new NotImplementedException(); } /// /// 启动服务器 /// public void Start() { _sc.StartServer(_port); } /// /// 是否启用访问控制 IP策略 /// /// public void UserAccessControl(bool enabled) { EnableAccessControl = enabled; } //TODO 实现访问黑名单 基于IP控制策略 /// /// 检查访问黑名单 /// private bool CheckIfBlocked(string ipAddress) { return AccessManager.Instance.CheckBlackList(ipAddress); } /// /// 设置最大接收文件大小 /// /// public void SetMaxFileSize(long fileSize) { _maxFileSize = fileSize; } /// /// 设置最大请求大小 /// /// public void SetMaxRequestSize(long size) { _maxRequestSize = size; } /// /// 设置临时文件目录 /// /// public void SetTempPath(string path) { _tempPath = path; } /// /// 设置首页 /// /// public void SetIndexPage(string pattern) { _indexPageMatchPattern = pattern; } /// /// 关闭服务器 /// public void Shutdown() { _sc.StopServer(); } } }