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

Last change on this file since 274 was 250, checked in by alloc, 9 years ago

Fixes 5_7_9

File size: 7.9 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Collections.Specialized;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Reflection;
8using System.Text;
9using System.Threading;
10using UnityEngine;
11
12using AllocsFixes.NetConnections.Servers.Web.Handlers;
13
14namespace AllocsFixes.NetConnections.Servers.Web
15{
16 public class Web : IConsoleServer {
17 private const int GUEST_PERMISSION_LEVEL = 2000;
18 private readonly HttpListener _listener = new HttpListener ();
19 private Dictionary<string, PathHandler> handlers = new Dictionary<string, PathHandler> ();
20 public static int handlingCount = 0;
21 public static int currentHandlers = 0;
22 private string dataFolder;
23 private bool useStaticCache = false;
24
25 public bool isSslRedirected {
26 private set;
27 get;
28 }
29
30 public ConnectionHandler connectionHandler;
31
32 public Web () {
33 try {
34 int webPort = GamePrefs.GetInt (EnumGamePrefs.ControlPanelPort);
35 if (webPort < 1 || webPort > 65533) {
36 Log.Out ("Webserver not started (ControlPanelPort not within 1-65533)");
37 return;
38 }
39 if (!Directory.Exists (Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) + "/webserver")) {
40 Log.Out ("Webserver not started (folder \"webserver\" not found in WebInterface mod folder)");
41 return;
42 }
43
44 // TODO: Read from config
45 isSslRedirected = false;
46 useStaticCache = false;
47
48 dataFolder = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) + "/webserver";
49
50 if (!HttpListener.IsSupported) {
51 Log.Out ("Webserver not started (needs Windows XP SP2, Server 2003 or later or Mono)");
52 return;
53 }
54
55 handlers.Add (
56 "/index.htm",
57 new SimpleRedirectHandler ("/static/index.html"));
58 handlers.Add (
59 "/favicon.ico",
60 new SimpleRedirectHandler ("/static/favicon.ico"));
61 handlers.Add (
62 "/session/",
63 new SessionHandler (
64 "/session/",
65 dataFolder,
66 this)
67 );
68 handlers.Add (
69 "/userstatus",
70 new UserStatusHandler ()
71 );
72 if (useStaticCache) {
73 handlers.Add (
74 "/static/",
75 new StaticHandler (
76 "/static/",
77 dataFolder,
78 new AllocsFixes.FileCache.SimpleCache (),
79 true)
80 );
81 } else {
82 handlers.Add (
83 "/static/",
84 new StaticHandler (
85 "/static/",
86 dataFolder,
87 new AllocsFixes.FileCache.DirectAccess (),
88 true)
89 );
90 }
91
92 handlers.Add (
93 "/itemicons/",
94 new ItemIconHandler (
95 "/itemicons/",
96 true)
97 );
98
99 handlers.Add (
100 "/map/",
101 new StaticHandler (
102 "/map/",
103 GameUtils.GetSaveGameDir () + "/map",
104 MapRendering.MapRendering.GetTileCache (),
105 false,
106 "web.map")
107 );
108
109 handlers.Add (
110 "/api/",
111 new ApiHandler ("/api/")
112 );
113
114 connectionHandler = new ConnectionHandler (this);
115
116 _listener.Prefixes.Add (String.Format ("http://*:{0}/", webPort + 2));
117 _listener.Start ();
118
119 SdtdConsole.Instance.RegisterServer (this);
120
121 _listener.BeginGetContext (new AsyncCallback (HandleRequest), _listener);
122
123 Log.Out ("Started Webserver on " + (webPort + 2));
124 } catch (Exception e) {
125 Log.Out ("Error in Web.ctor: " + e);
126 }
127 }
128
129 private void HandleRequest (IAsyncResult result) {
130 if (_listener.IsListening) {
131 Interlocked.Increment (ref handlingCount);
132 Interlocked.Increment (ref currentHandlers);
133 HttpListenerContext ctx = _listener.EndGetContext (result);
134 _listener.BeginGetContext (new AsyncCallback (HandleRequest), _listener);
135 try {
136 HttpListenerRequest request = ctx.Request;
137 HttpListenerResponse response = ctx.Response;
138
139 response.ProtocolVersion = new Version ("1.1");
140
141 WebConnection conn;
142 int permissionLevel = DoAuthentication (request, out conn);
143
144
145 //Log.Out ("Login status: conn!=null: {0}, permissionlevel: {1}", conn != null, permissionLevel);
146
147
148 if (conn != null) {
149 Cookie cookie = new Cookie ("sid", conn.SessionID, "/");
150 cookie.Expired = false;
151 cookie.Expires = new DateTime (2020, 1, 1);
152 cookie.HttpOnly = true;
153 cookie.Secure = false;
154 response.AppendCookie (cookie);
155 }
156
157 if (request.Url.AbsolutePath.Length < 2) {
158 handlers ["/index.htm"].HandleRequest (request, response, conn, permissionLevel);
159 return;
160 } else {
161 foreach (KeyValuePair<string, PathHandler> kvp in handlers) {
162 if (request.Url.AbsolutePath.StartsWith (kvp.Key)) {
163 if (!kvp.Value.IsAuthorizedForHandler (conn, permissionLevel)) {
164 response.StatusCode = (int)HttpStatusCode.Forbidden;
165 if (conn != null) {
166 //Log.Out ("Web.HandleRequest: user '{0}' not allowed to access '{1}'", conn.SteamID, kvp.Value.ModuleName);
167 } else {
168 //Log.Out ("Web.HandleRequest: unidentified user from '{0}' not allowed to access '{1}'", request.RemoteEndPoint.Address, kvp.Value.ModuleName);
169 }
170 } else {
171 kvp.Value.HandleRequest (request, response, conn, permissionLevel);
172 }
173 return;
174 }
175 }
176 }
177
178 Log.Out ("Error in Web.HandleRequest(): No handler found for path \"" + request.Url.AbsolutePath + "\"");
179 response.StatusCode = (int)HttpStatusCode.NotFound;
180 } catch (IOException e) {
181 if (e.InnerException is SocketException) {
182 Log.Out ("Error in Web.HandleRequest(): Remote host closed connection: " + e.InnerException.Message);
183 } else {
184 Log.Out ("Error (IO) in Web.HandleRequest(): " + e);
185 }
186 } catch (Exception e) {
187 Log.Out ("Error in Web.HandleRequest(): " + e);
188 } finally {
189 if (ctx != null) {
190 ctx.Response.Close ();
191 }
192 Interlocked.Decrement (ref currentHandlers);
193 }
194 }
195 }
196
197 private int DoAuthentication (HttpListenerRequest _req, out WebConnection _con) {
198 _con = null;
199
200 string sessionId = null;
201 if (_req.Cookies ["sid"] != null) {
202 sessionId = _req.Cookies ["sid"].Value;
203 }
204
205 if (!string.IsNullOrEmpty (sessionId)) {
206 WebConnection con = connectionHandler.IsLoggedIn (sessionId, _req.RemoteEndPoint.Address.ToString ());
207 if (con != null) {
208 _con = con;
209 return GameManager.Instance.adminTools.GetAdminToolsClientInfo (_con.SteamID.ToString ()).PermissionLevel;
210 }
211 }
212
213 if (_req.QueryString ["adminuser"] != null && _req.QueryString ["admintoken"] != null) {
214 WebPermissions.AdminToken admin = WebPermissions.Instance.GetWebAdmin (_req.QueryString ["adminuser"], _req.QueryString ["admintoken"]);
215 if (admin != null) {
216 return admin.permissionLevel;
217 } else {
218 Log.Warning ("Invalid Admintoken used from " + _req.RemoteEndPoint.ToString ());
219 }
220 }
221
222 if (_req.Url.AbsolutePath.StartsWith ("/session/verify")) {
223 ulong id = OpenID.Validate (_req);
224 if (id > 0) {
225 WebConnection con = connectionHandler.LogIn (id, _req.RemoteEndPoint.Address.ToString ());
226 _con = con;
227 int level = GameManager.Instance.adminTools.GetAdminToolsClientInfo (id.ToString ()).PermissionLevel;
228 Log.Out ("Steam OpenID login from {0} with ID {1}, permission level {2}", _req.RemoteEndPoint.ToString (), con.SteamID, level);
229 return level;
230 } else {
231 Log.Out ("Steam OpenID login failed from {0}", _req.RemoteEndPoint.ToString ());
232 }
233 }
234
235 return GUEST_PERMISSION_LEVEL;
236 }
237
238 public void Disconnect () {
239 try {
240 _listener.Stop ();
241 _listener.Close ();
242 } catch (Exception e) {
243 Log.Out ("Error in Web.Disconnect: " + e);
244 }
245 }
246
247 public void SendLine (string line) {
248 connectionHandler.SendLine (line);
249 }
250
251 public void SendLog (string text, string trace, UnityEngine.LogType type) {
252 // Do nothing, handled by LogBuffer internally
253 }
254
255 public static void SetResponseTextContent (HttpListenerResponse resp, string text) {
256 byte[] buf = Encoding.UTF8.GetBytes (text);
257 resp.ContentLength64 = buf.Length;
258 resp.ContentType = "text/html";
259 resp.ContentEncoding = Encoding.UTF8;
260 resp.OutputStream.Write (buf, 0, buf.Length);
261 }
262
263 }
264}
Note: See TracBrowser for help on using the repository browser.