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 }