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

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

Server fixes

File size: 5.3 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Net;
5using System.Net.Sockets;
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> ();
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
21 public Web ()
22 {
23 try {
24 int webPort = GamePrefs.GetInt (EnumGamePrefs.ControlPanelPort);
25 if (webPort < 1 || webPort > 65533) {
26 Log.Out ("Webserver not started (ControlPanelPort not within 1-65534)");
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
34 if (!HttpListener.IsSupported) {
35 Log.Out ("Webserver not started (needs Windows XP SP2, Server 2003 or later or Mono)");
36 return;
37 }
38
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 );
58 handlers.Add ("/api/", new ApiHandler ("/api/"));
59
60 _listener.Prefixes.Add (String.Format ("http://*:{0}/", webPort + 2));
61 authEnabled = File.Exists (Application.dataPath + "/../webserver/protect");
62 if (authEnabled)
63 _listener.AuthenticationSchemes = AuthenticationSchemes.Basic;
64 _listener.Start ();
65 _listener.Realm = realm;
66
67 NetTelnetServer.RegisterServer (this);
68
69 _listener.BeginGetContext (new AsyncCallback (HandleRequest), _listener);
70
71 Log.Out ("Started Webserver on " + (webPort + 2) + " (authentication " + (authEnabled ? "enabled" : "disabled") + ")");
72 } catch (Exception e) {
73 Log.Out ("Error in Web.ctor: " + e);
74 }
75 }
76
77 private void HandleRequest (IAsyncResult result)
78 {
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");
86
87 HttpListenerBasicIdentity user = Authorize (ctx);
88
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 }
99 }
100 }
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 + "\"";
107 }
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);
123 }
124 }
125 }
126
127 private HttpListenerBasicIdentity Authorize (HttpListenerContext ctx)
128 {
129 try {
130 return (HttpListenerBasicIdentity)ctx.User.Identity;
131 } catch (NullReferenceException) {
132 return null;
133 }
134 }
135
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
146 public void SendLine (string line)
147 {
148 try {
149 //Log.Out ("NOT IMPLEMENTED: Web.WriteToClient");
150 } catch (Exception e) {
151 Log.Out ("Error in Web.WriteToClient: " + e);
152 }
153 }
154
155 public void SendLog (string text, string trace, UnityEngine.LogType type)
156 {
157 throw new System.NotImplementedException ();
158 }
159
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
169 }
170}
Note: See TracBrowser for help on using the repository browser.