source: binary-improvements/7dtd-server-fixes/src/NetConnections/Servers/Web/Web.cs@ 215

Last change on this file since 215 was 202, checked in by alloc, 10 years ago

Server fixes

File size: 5.3 KB
RevLine 
[133]1using System;
2using System.Collections.Generic;
[168]3using System.IO;
[133]4using System.Net;
[202]5using System.Net.Sockets;
[133]6using System.Text;
7using System.Threading;
8using UnityEngine;
9
10namespace AllocsFixes.NetConnections.Servers.Web
11{
12 public class Web : IServer
13 {
14 private readonly HttpListener _listener = new HttpListener ();
15 private Dictionary<string, PathHandler> handlers = new Dictionary<string, PathHandler> ();
[172]16 private bool authEnabled = false;
17 private string realm = "7dtd Admin Panel";
[202]18 public static int handlingCount = 0;
19 public static int currentHandlers = 0;
[133]20
[182]21 public Web ()
[133]22 {
23 try {
[182]24 int webPort = GamePrefs.GetInt (EnumGamePrefs.ControlPanelPort);
[185]25 if (webPort < 1 || webPort > 65533) {
26 Log.Out ("Webserver not started (ControlPanelPort not within 1-65534)");
[182]27 return;
28 }
29 if (!Directory.Exists (Application.dataPath + "/../webserver")) {
30 Log.Out ("Webserver not started (folder \"webserver\" not found in game folder)");
31 return;
32 }
33
[183]34 if (!HttpListener.IsSupported) {
35 Log.Out ("Webserver not started (needs Windows XP SP2, Server 2003 or later or Mono)");
36 return;
37 }
[133]38
[199]39 handlers.Add (
40 "/index.htm",
41 new SimpleRedirectHandler ("/static/index.html"));
42 handlers.Add (
43 "/static/",
44 new StaticHandler (
45 "/static/",
46 Application.dataPath + "/../webserver",
47 new AllocsFixes.FileCache.DirectAccess (),
48 true)
49 ); // TODO: Enable cache
50 handlers.Add (
51 "/map/",
52 new StaticHandler (
53 "/map/",
54 StaticDirectories.GetSaveGameDir () + "/map",
55 MapRendering.MapRendering.Instance.TileCache,
56 false)
57 );
[154]58 handlers.Add ("/api/", new ApiHandler ("/api/"));
[133]59
[182]60 _listener.Prefixes.Add (String.Format ("http://*:{0}/", webPort + 2));
[172]61 authEnabled = File.Exists (Application.dataPath + "/../webserver/protect");
62 if (authEnabled)
[168]63 _listener.AuthenticationSchemes = AuthenticationSchemes.Basic;
[133]64 _listener.Start ();
[172]65 _listener.Realm = realm;
[133]66
[199]67 NetTelnetServer.RegisterServer (this);
[182]68
[202]69 _listener.BeginGetContext (new AsyncCallback (HandleRequest), _listener);
[182]70
71 Log.Out ("Started Webserver on " + (webPort + 2) + " (authentication " + (authEnabled ? "enabled" : "disabled") + ")");
[133]72 } catch (Exception e) {
73 Log.Out ("Error in Web.ctor: " + e);
74 }
75 }
76
[202]77 private void HandleRequest (IAsyncResult result)
[133]78 {
[202]79 if (_listener.IsListening) {
80 Interlocked.Increment(ref handlingCount);
81 Interlocked.Increment(ref currentHandlers);
82 HttpListenerContext ctx = _listener.EndGetContext (result);
83 _listener.BeginGetContext (new AsyncCallback (HandleRequest), _listener);
84 try {
85 ctx.Response.ProtocolVersion = new Version ("1.1");
[133]86
[202]87 HttpListenerBasicIdentity user = Authorize (ctx);
[134]88
[202]89 if (!authEnabled || (user.Name.ToLower ().Equals ("admin") && user.Password.Equals (GamePrefs.GetString (EnumGamePrefs.ControlPanelPassword)))) {
90 if (ctx.Request.Url.AbsolutePath.Length < 2) {
91 handlers ["/index.htm"].HandleRequest (ctx.Request, ctx.Response, user);
92 return;
93 } else {
94 foreach (KeyValuePair<string, PathHandler> kvp in handlers) {
95 if (ctx.Request.Url.AbsolutePath.StartsWith (kvp.Key)) {
96 kvp.Value.HandleRequest (ctx.Request, ctx.Response, user);
97 return;
98 }
[172]99 }
[133]100 }
[202]101
102 Log.Out ("Error in Web.HandleRequest(): No handler found for path \"" + ctx.Request.Url.AbsolutePath + "\"");
103 ctx.Response.StatusCode = (int)HttpStatusCode.NotFound;
104 } else {
105 ctx.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
106 ctx.Response.Headers ["WWW-Authenticate"] = "Basic realm=\"" + realm + "\"";
[133]107 }
[202]108 } catch (IOException e) {
109 if (e.InnerException is SocketException) {
110 if (e.InnerException.Message.Contains ("forcibly closed") || e.InnerException.Message.Contains ("socket has been shut down"))
111 Log.Out ("Error in Web.HandleRequest(): Remote host closed connection");
112 else
113 Log.Out ("Error (IO->Socket) in Web.HandleRequest(): " + e);
114 } else {
115 Log.Out ("Error (IO) in Web.HandleRequest(): " + e);
116 }
117 } catch (Exception e) {
118 Log.Out ("Error in Web.HandleRequest(): " + e);
119 } finally {
120 if (ctx != null)
121 ctx.Response.OutputStream.Close ();
122 Interlocked.Decrement(ref currentHandlers);
[133]123 }
124 }
125 }
126
[154]127 private HttpListenerBasicIdentity Authorize (HttpListenerContext ctx)
[134]128 {
129 try {
[154]130 return (HttpListenerBasicIdentity)ctx.User.Identity;
[134]131 } catch (NullReferenceException) {
[154]132 return null;
[134]133 }
134 }
135
[133]136 public void Disconnect ()
137 {
138 try {
139 _listener.Stop ();
140 _listener.Close ();
141 } catch (Exception e) {
142 Log.Out ("Error in Web.Disconnect: " + e);
143 }
144 }
145
[190]146 public void SendLine (string line)
[133]147 {
148 try {
[142]149 //Log.Out ("NOT IMPLEMENTED: Web.WriteToClient");
[133]150 } catch (Exception e) {
151 Log.Out ("Error in Web.WriteToClient: " + e);
152 }
153 }
154
[190]155 public void SendLog (string text, string trace, UnityEngine.LogType type)
[133]156 {
[190]157 throw new System.NotImplementedException ();
[133]158 }
159
[163]160 public static void SetResponseTextContent (HttpListenerResponse resp, string text)
161 {
162 byte[] buf = Encoding.UTF8.GetBytes (text);
163 resp.ContentLength64 = buf.Length;
164 resp.ContentType = "text/html";
165 resp.ContentEncoding = Encoding.UTF8;
166 resp.OutputStream.Write (buf, 0, buf.Length);
167 }
168
[133]169 }
170}
Note: See TracBrowser for help on using the repository browser.