1 /*  Copyright (C) 2013, 2015  Vladimir Panteleev <vladimir@thecybershadow.net>
2  *
3  *  This program is free software: you can redistribute it and/or modify
4  *  it under the terms of the GNU Affero General Public License as
5  *  published by the Free Software Foundation, either version 3 of the
6  *  License, or (at your option) any later version.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU Affero General Public License for more details.
12  *
13  *  You should have received a copy of the GNU Affero General Public License
14  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 module http;
18 
19 import std.algorithm;
20 import std.array;
21 import std.exception;
22 import std.conv;
23 import std.file;
24 import std..string;
25 
26 import ae.net.http.server;
27 import ae.net.http.responseex;
28 import ae.utils.array;
29 
30 import common;
31 
32 alias std..string.indexOf indexOf;
33 
34 class WormNETHttpServer
35 {
36 	HttpServer server;
37 
38 	this()
39 	{
40 		server = new HttpServer;
41 		server.handleRequest = &onRequest;
42 	}
43 
44 	struct Game
45 	{
46 		int id;
47 		string name;
48 		string host;
49 		string address;
50 		string password;
51 		string channel;
52 		string location;
53 		string type;
54 	}
55 	Game[] games;
56 	int gameCounter;
57 
58 	void onRequest(HttpRequest request, HttpServerConnection conn)
59 	{
60 		auto response = new HttpResponseEx();
61 
62 		try
63 		{
64 			auto pathStr = request.resource;
65 			enforce(pathStr.startsWith('/'), "Invalid path");
66 			UrlParameters parameters;
67 			if (pathStr.indexOf('?') >= 0)
68 			{
69 				auto p = pathStr.indexOf('?');
70 				parameters = decodeUrlParameters(pathStr[p+1..$]);
71 				pathStr = pathStr[0..p];
72 			}
73 			auto path = pathStr[1..$].split("/");
74 
75 			if (path.length == 2 && path[0] == "wormageddonweb")
76 			{
77 				string html = "<NOTHING>";
78 				switch (path[1])
79 				{
80 					case "Login.asp":
81 						html = "<CONNECT %s>".format(configuration.irc.IP ? configuration.irc.IP : conn.tcp.localAddress.toAddrString);
82 						if (configuration.http.newsFileName.exists)
83 							html ~= "\r\n<MOTD>\r\n%s\r\n</MOTD>".format(configuration.http.newsFileName.readText);
84 						break;
85 					case "RequestChannelScheme.asp":
86 						html = "<SCHEME=%s>".format(configuration.channels.aaGet(parameters.aaGet("Channel")).scheme);
87 						break;
88 					case "Game.asp":
89 						switch (parameters.aaGet("Cmd"))
90 						{
91 							case "Create":
92 								gameCounter++;
93 								games ~= Game(
94 									gameCounter,
95 									parameters.aaGet("Name")[0..min($, 29)],
96 									parameters.aaGet("Nick"),
97 									parameters.aaGet("HostIP"),
98 									parameters.get("Pwd", null),
99 									parameters.aaGet("Chan"),
100 									parameters.aaGet("Loc"),
101 									parameters.aaGet("Type"),
102 								);
103 								response.headers["SetGameId"] = ": %d".format(gameCounter);
104 								break;
105 							case "Close":
106 							{
107 								auto id = parameters.aaGet("GameID").to!int;
108 								games = games.filter!(game => game.id != id).array;
109 								break;
110 							}
111 							case "Failed":
112 								break;
113 							default:
114 								return conn.sendResponse(response.writeError(HttpStatusCode.BadRequest));
115 						}
116 						break;
117 					case "GameList.asp":
118 						html = "<GAMELISTSTART>\r\n" ~
119 							games
120 								.filter!(game => game.channel == parameters.aaGet("Channel"))
121 								.map!(game => "<GAME %s %s %s %d %d %d %d %d><BR>\r\n".format(
122 									game.name, game.host, game.address, game.location, 1 /* open */, game.password ? 1 : 0, game.id, game.type
123 								))
124 								.join() ~
125 							"<GAMELISTEND>\r\n";
126 						break;
127 					case "UpdatePlayerInfo.asp":
128 						break;
129 					default:
130 						return conn.sendResponse(response.writeError(HttpStatusCode.NotFound));
131 				}
132 				return conn.sendResponse(response.serveData(html));
133 			}
134 			else
135 				return conn.sendResponse(response.serveFile(pathStr[1..$], "wwwroot/"));
136 		}
137 		catch (FileException e)
138 			return conn.sendResponse(response.writeError(HttpStatusCode.NotFound           , e.msg));
139 		catch (Exception e)
140 			return conn.sendResponse(response.writeError(HttpStatusCode.InternalServerError, e.toString));
141 	}
142 }