1 /* Copyright (C) 2013, 2015, 2018, 2020 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 core.time; 20 21 import std.algorithm; 22 import std.array; 23 import std.datetime : SysTime, Clock; 24 import std.exception; 25 import std.conv; 26 import std.file; 27 import std.string; 28 29 import ae.net.http.server; 30 import ae.net.http.responseex; 31 import ae.utils.array; 32 33 import common; 34 35 alias std..string.indexOf indexOf; 36 37 class WormNETHttpServer 38 { 39 HttpServer server; 40 41 this() 42 { 43 server = new HttpServer; 44 server.handleRequest = &onRequest; 45 } 46 47 struct Game 48 { 49 int id; 50 string name; 51 string host; 52 string address; 53 string password; 54 string channel; 55 string location; 56 string type; 57 SysTime created; 58 } 59 Game[] games; 60 int gameCounter; 61 62 enum gameTimeout = 5.minutes; 63 64 void onRequest(HttpRequest request, HttpServerConnection conn) 65 { 66 auto response = new HttpResponseEx(); 67 auto now = Clock.currTime(); 68 69 try 70 { 71 auto pathStr = request.resource; 72 enforce(pathStr.startsWith('/'), "Invalid path"); 73 UrlParameters parameters; 74 if (pathStr.indexOf('?') >= 0) 75 { 76 auto p = pathStr.indexOf('?'); 77 parameters = decodeUrlParameters(pathStr[p+1..$]); 78 pathStr = pathStr[0..p]; 79 } 80 auto path = pathStr[1..$].split("/"); 81 82 if (path.length == 2 && path[0] == "wormageddonweb") 83 { 84 string html = "<NOTHING>"; 85 switch (path[1]) 86 { 87 case "Login.asp": 88 html = "<CONNECT %s%s>".format( 89 configuration.irc.IP ? configuration.irc.IP : conn.tcp.localAddress.toAddrString, 90 configuration.http.connectPort ? ":" ~ configuration.http.connectPort : "", 91 ); 92 if (configuration.http.newsFileName.exists) 93 html ~= "\r\n<MOTD>\r\n%s\r\n</MOTD>".format(configuration.http.newsFileName.readText); 94 break; 95 case "RequestChannelScheme.asp": 96 html = "<SCHEME=%s>".format(configuration.channels.aaGet(parameters.aaGet("Channel")).scheme); 97 break; 98 case "Game.asp": 99 switch (parameters.aaGet("Cmd")) 100 { 101 case "Create": 102 gameCounter++; 103 games ~= Game( 104 gameCounter, 105 parameters.aaGet("Name")[0..min($, 29)], 106 parameters.aaGet("Nick"), 107 parameters.aaGet("HostIP"), 108 parameters.get("Pwd", null), 109 parameters.aaGet("Chan"), 110 parameters.aaGet("Loc"), 111 parameters.aaGet("Type"), 112 now, 113 ); 114 response.headers["SetGameId"] = ": %d".format(gameCounter); 115 break; 116 case "Close": 117 { 118 auto id = parameters.aaGet("GameID").to!int; 119 games = games.filter!(game => game.id != id).array; 120 break; 121 } 122 case "Failed": 123 break; 124 default: 125 return conn.sendResponse(response.writeError(HttpStatusCode.BadRequest)); 126 } 127 break; 128 case "GameList.asp": 129 games = games.filter!(game => now - game.created < gameTimeout).array; 130 html = "<GAMELISTSTART>\r\n" ~ 131 games 132 .filter!(game => game.channel == parameters.aaGet("Channel")) 133 .map!(game => "<GAME %s %s %s %s %d %d %d %s><BR>\r\n".format( 134 game.name, game.host, game.address, game.location, 1 /* open */, game.password ? 1 : 0, game.id, game.type 135 )) 136 .join() ~ 137 "<GAMELISTEND>\r\n"; 138 break; 139 case "UpdatePlayerInfo.asp": 140 break; 141 default: 142 return conn.sendResponse(response.writeError(HttpStatusCode.NotFound)); 143 } 144 return conn.sendResponse(response.serveData(html)); 145 } 146 else 147 return conn.sendResponse(response.serveFile(pathStr[1..$], "wwwroot/")); 148 } 149 catch (FileException e) 150 return conn.sendResponse(response.writeError(HttpStatusCode.NotFound , e.msg)); 151 catch (Exception e) 152 return conn.sendResponse(response.writeError(HttpStatusCode.InternalServerError, e.toString)); 153 } 154 }