source: binary-improvements/MapRendering/Web/Web.cs@ 243

Last change on this file since 243 was 238, checked in by alloc, 9 years ago

Server fixes for A12

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