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

Last change on this file since 309 was 309, checked in by alloc, 2 years ago

Fixes 14_16_21

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