/* ZazouMiniWebServer Copyright (C) 2003-2008 Xavier Garreau This file is part of ZazouMiniWebServer. ZazouMiniWebServer is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. ZazouMiniWebServer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with ZazouMiniWebServer; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "stdafx.h" #include "ZMWSConfFileParser.h" BOOL ZMWSConfFileParser::HandleVar(ZMWSConfig& config, ZMWSMIME& mime_manager, std::string& var, std::string& val) { BOOL OptIsOK = FALSE; // curr_config_context can be Main, a domain name or MimeType std::string::size_type first_word_end = var.find(':'); if (first_word_end == std::string::npos) return FALSE; std::string var_name; std::string extrainfo; std::string::size_type var_name_begin; if (var.substr(0, first_word_end)=="Main") { OptIsOK = TRUE; curr_config_context = "Main"; var_name_begin = first_word_end+1; } if (var.substr(0, first_word_end)=="Include") { OptIsOK = TRUE; curr_config_context = "Include"; var_name_begin = 0; } if (var.substr(0, first_word_end)=="MimeType") { OptIsOK = TRUE; curr_config_context = "Mime"; var_name_begin = first_word_end+1; } if (var.substr(0, first_word_end)=="Handler") { OptIsOK = TRUE; curr_config_context = "Handler"; var_name_begin = first_word_end+1; } if (var.substr(0, first_word_end)=="TRUECGIHandler") { OptIsOK = TRUE; curr_config_context = "TRUECGIHandler"; var_name_begin = first_word_end+1; } if (var.substr(0, first_word_end)=="ZMWSSAPIHandler") { OptIsOK = TRUE; curr_config_context = "ZMWSSAPIHandler"; var_name_begin = first_word_end+1; } if (var.substr(0, first_word_end)=="VirtualHost") { OptIsOK = TRUE; std::string::size_type vhost_name_begin = first_word_end+1; std::string::size_type vhost_name_end = var.find(':', vhost_name_begin); if (vhost_name_end == std::string::npos) return FALSE; curr_config_context = "VirtualHost"; extrainfo = var.substr(vhost_name_begin, vhost_name_end-vhost_name_begin); var_name_begin = vhost_name_end+1; } if (var.substr(0, first_word_end)=="PerUrl") { OptIsOK = TRUE; std::string::size_type perurl_name_begin = first_word_end+1; std::string::size_type perurl_name_end = var.find(':', perurl_name_begin); if (perurl_name_end == std::string::npos) return FALSE; curr_config_context = "PerUrl"; extrainfo = var.substr(perurl_name_begin, perurl_name_end-perurl_name_begin); var_name_begin = perurl_name_end+1; } if (!OptIsOK) return FALSE; if (!curr_config_context.length()) return FALSE; // Recherche du nom de variable var_name = var.substr(var_name_begin); if (!((curr_config_context == "Mime") || var_name.length())) return FALSE; // Config globale if (curr_config_context == "Main") { OptIsOK = MainApplyVar(config, var_name, val); } else if (curr_config_context == "Include") { ZMWSConfFileParser* cfp = new ZMWSConfFileParser(); OptIsOK = cfp->Parse(config, mime_manager, val.c_str()); delete cfp; } else if (curr_config_context == "Mime") { OptIsOK = MimeApplyVar(mime_manager, var_name, val); } else if (curr_config_context == "Handler") { OptIsOK = HandlerApplyVar(config, var_name, val); } else if (curr_config_context == "TRUECGIHandler") { OptIsOK = TRUECGIHandlerApplyVar(config, var_name, val); } else if (curr_config_context == "ZMWSSAPIHandler") { OptIsOK = ZMWSSAPIHandlerApplyVar(config, var_name, val); } else if (curr_config_context == "VirtualHost") { OptIsOK = VHostApplyVar(config, extrainfo, var_name, val); } else if (curr_config_context == "PerUrl") { OptIsOK = PerUrlApplyVar(config, extrainfo, var_name, val); } return OptIsOK; } BOOL ZMWSConfFileParser::GetConfigVar(std::string& var, std::string& val) { char c = 0; BOOL isVal = FALSE; BOOL ignoreSpace = TRUE; BOOL escapeOne = FALSE; BOOL isComment = FALSE; var = val = ""; while ((conf_file.get(c)) && (c!='\n')) { if (isComment) continue; if (c=='\t') c=' '; if (c=='\r') c=' '; if (ignoreSpace && (c==' ')) continue; if (c=='\\' && !escapeOne) { escapeOne = TRUE; continue; } if (c=='\"' && !escapeOne) { ignoreSpace = !ignoreSpace; continue; } if ((c=='=') && !isVal && !escapeOne) { isVal = TRUE; continue; } if (c=='#' && !escapeOne) { isComment = TRUE; continue; } escapeOne = FALSE; if (isVal) val += c; else var += c; } // Cas de la ligne terminale avec val de longueur vide et \n final manquant if (conf_file.eof()) { conf_file.close(); return TRUE; } return ((c=='\n') || (var.length() && val.length())); } BOOL ZMWSConfFileParser::Parse(ZMWSConfig& config, ZMWSMIME& mime_manager, const char* filepath) { BOOL OptsOk = TRUE; std::string var, val, msg; std::string fp; if (!filepath) { fp = config.GetPathToConfigFile(); } else { fp = filepath; } conf_file.open(fp.c_str()); if (!conf_file) { print_dbg(("No config file found. Tried "+fp+"\n").c_str()); return TRUE; } else { print_dbg(("Using config file : "+fp+"\n").c_str()); } while ((conf_file.is_open()) && (GetConfigVar(var, val))) { if (var.length()) { if (!HandleVar(config, mime_manager, var, val)) { print_dbg(("CONFIG SYNTAX ERROR : "+var+":"+val+"\n").c_str()); OptsOk = FALSE; } } } return OptsOk; } void ZMWSConfFileParser::PrintError(const std::string& option, const std::string& error_text) { std::string tmpS; tmpS = "\n----------------------------------------\n"; tmpS += "ERROR : option "; tmpS += option; tmpS += "\nERROR MESSAGE: "; tmpS += error_text; tmpS += "\n----------------------------------------\n"; print_dbg(tmpS.c_str()); } void ZMWSConfFileParser::PrintWarning(const std::string& warning_text) { std::string tmpS; tmpS = "\n----------------------------------------\n"; tmpS += "WARNING: "; tmpS += warning_text; tmpS += "\n----------------------------------------\n"; print_dbg(tmpS.c_str()); } BOOL ZMWSConfFileParser::PerUrlApplyVar(ZMWSConfig& config, const std::string& url, const std::string& var, const std::string& val) { BOOL OptIsOk = TRUE; ZMWSPerUrlConfig puc; config.GetPerUrlConfig(url, puc, TRUE); std::string varkey, varvar; std::string::size_type varkey_end = var.find(':'); if (varkey_end == std::string::npos) return FALSE; varkey = var.substr(0, varkey_end); varvar = var.substr(varkey_end+1); print_dbg (("if url like "+url+"%, "+varkey+" "+val+" for "+varvar+"\n").c_str()); if (varkey == "Handler") { ZMWSHandler handler; handler.handlerType = handler.DEFAULT; handler.handlerPath = val; puc.AddHandler(varvar, handler); config.SetPerUrlConfig(url, puc); } return OptIsOk; } BOOL ZMWSConfFileParser::VHostApplyVar(ZMWSConfig& config, const std::string& vhost, const std::string& var, const std::string& val) { BOOL OptIsOk = TRUE; ZMWSVHostConfig vhc; if (!config.GetVHostConfig(vhost, vhc)) { config.CreateDefaultVHost(vhost); if (!config.GetVHostConfig(vhost, vhc)) { print_dbg(("ERROR: Could not create default VHost " + vhost + "\n").c_str()); return FALSE; } } /* * Indexing */ if (var == "noindex") { if ((val=="1") || (val=="true")) vhc.canIndex = false; else vhc.canIndex = true; config.SetVHostConfig(vhc.domain, vhc); return OptIsOk; } /* * Reverse DNS */ if (var == "norv") { if ((val=="1") || (val=="true")) vhc.reverseDNS = false; else vhc.reverseDNS = true; config.SetVHostConfig(vhc.domain, vhc); return OptIsOk; } if (var == "revdns") { if ((val=="1") || (val=="true")) vhc.reverseDNS = true; else vhc.reverseDNS = false; config.SetVHostConfig(vhc.domain, vhc); return OptIsOk; } /* * Web Dir */ if (var == "webdir") { if (!config.SetDocumentRoot(val, vhc.domain)) { PrintError(var.c_str(), "Bad path !"); OptIsOk = FALSE; } return OptIsOk; } /* * Logs Dir */ if (var == "logsdir") { if (!config.SetLogsDir(val, vhc.domain)) { PrintError(var.c_str(), "Bad path !"); OptIsOk = FALSE; } return OptIsOk; } /* * Alias */ if (var == "alias") { config.AddVHostAlias(val, vhc.domain); print_dbg(("New alias for "+vhc.domain+" : "+val+"\n").c_str()); return OptIsOk; } /* * Default charset */ if (var == "defcharset") { config.SetDefaultCharset(val, vhc.domain); return OptIsOk; } /* * Allowed Client IP */ if (var == "allowfrom") { config.SetAllowFrom(val, vhc.domain); return OptIsOk; } /* * Maximum kB per maxKBytesDTime */ if (var == "maxKBytes") { DWORD maxKBytes = strtoul(val.c_str(), NULL, 10); vhc.maxKBytes=maxKBytes; config.SetVHostConfig(vhc.domain, vhc); return OptIsOk; } /* * Maximum kB per maxKBytesDTime */ if (var == "maxKBytesDTime") { DWORD maxKBytesDTime = strtoul(val.c_str(), NULL, 10); vhc.maxKBytesDTime=maxKBytesDTime; config.SetVHostConfig(vhc.domain, vhc); return OptIsOk; } /* complex options */ std::string varkey, varvar; std::string::size_type varkey_end = var.find(':'); if (varkey_end == std::string::npos) return OptIsOk; { varkey = var.substr(0, varkey_end); varvar = var.substr(varkey_end+1); /* * Directory Aliases */ if (varkey == "diralias") { config.AddDirAlias(varvar, val, vhc.domain); return OptIsOk; } /* * Handlers */ if (varkey == "Handler") { ZMWSHandler handler; handler.handlerType = handler.DEFAULT; handler.handlerPath = val; config.AddHandler(varvar, handler, vhc.domain); } } return OptIsOk; } BOOL ZMWSConfFileParser::MainApplyVar(ZMWSConfig& config, const std::string& var, const std::string& val) { BOOL OptIsOk = TRUE; /* * Hide Console */ if (var == "hide") { if ((val=="1") || (val=="true")) { config.SetHideConsole(true); config.SetBeQuiet(true); } else { config.SetHideConsole(false); } return OptIsOk; } /* * Be Quiet */ if (var == "quiet") { if ((val=="1") || (val=="true")) { config.SetBeQuiet(true); } else { config.SetBeQuiet(false); } return OptIsOk; } /* * Can Stop */ if (var == "stop") { if ((val=="1") || (val=="true")) config.SetCanStop(true); else config.SetCanStop(false); return OptIsOk; } /* * Can Close Browser */ if (var == "closebrowser") { if ((val=="1") || (val=="true")) config.SetCloseBrowser(true); else config.SetCloseBrowser(false); return OptIsOk; } /* * Browsing */ if (var == "browse") { if ((val=="1") || (val=="true")) config.SetBrowseNow(true); else config.SetBrowseNow(false); return OptIsOk; } /* * Browser command */ if (var == "browsercmd") { config.SetBrowserCmd(val); return OptIsOk; } /* * Drop Clients (immediate close) */ if (var == "dropclients") { if ((val=="1") || (val=="true")) config.SetDropClients(true); else config.SetDropClients(false); return OptIsOk; } /* * Logging */ if (var == "nolog") { if ((val=="1") || (val=="true")) config.SetWriteLogs(false); else config.SetWriteLogs(true); return OptIsOk; } /* * Reverse DNS */ if (var == "norv") { if ((val=="1") || (val=="true")) config.SetReverseDNS(false); else config.SetReverseDNS(true); return OptIsOk; } if (var == "revdns") { if ((val=="1") || (val=="true")) config.SetReverseDNS(true); else config.SetReverseDNS(false); return OptIsOk; } /* * Indexing */ if (var == "noindex") { if ((val=="1") || (val=="true")) config.SetCanIndex(false); else config.SetCanIndex(true); return OptIsOk; } /* * Port */ if (var == "port") { if (val=="httpsonly" || val=="0") { config.SetPort(0); } else { DWORD port = strtoul(val.c_str(), NULL, 10); if (port) { config.SetPort(port); } else { PrintError(var.c_str(), "port MUST be a valid port (a number) !\n"); OptIsOk = FALSE; } } return OptIsOk; } /* * Don't try other ports */ if (var == "unique-port") { if ((val=="1") || (val=="true")) config.SetTry808xPorts(false); else config.SetTry808xPorts(true); return OptIsOk; } /* * Max connections */ if (var == "mc") { DWORD mc = strtoul(val.c_str(), NULL, 10); if (mc) { config.SetMaxClients(mc); } else { PrintError(var.c_str(), "maxConnections MUST be a number !\n"); OptIsOk = FALSE; } return OptIsOk; } /* * Default charset */ if (var == "defcharset") { config.SetDefaultCharset(val); return OptIsOk; } /* * IP to bind to */ if (var == "bind") { config.SetBindAddr(val); return OptIsOk; } /* * PHP Path */ if (var == "phppath") { if (!config.SetPathToPHP(val)) { PrintError(var.c_str(), "Bad path to php executable !\n"); OptIsOk = FALSE; } return OptIsOk; } /* * Web Dir */ if (var == "webdir") { if (!config.SetDocumentRoot(val)) { PrintError(var.c_str(), "Bad path !\n"); OptIsOk = FALSE; } return OptIsOk; } /* * Logs Dir */ if (var == "logsdir") { if (!config.SetLogsDir(val)) { PrintError(var.c_str(), "Bad path !\n"); OptIsOk = FALSE; } return OptIsOk; } /* * Directory Index Files * Start Page */ if (var == "startpage") { config.SetStartPages(val); return OptIsOk; } /* * Allowed Client IP */ if (var == "allowfrom") { config.SetAllowFrom(val); return OptIsOk; } /* * Server Token */ if (var == "pbtoken") { if (val == "noversion"){ config.SetPBToken(PBTOKEN_NOVERSION); } else if (val == "off") { config.SetPBToken(PBTOKEN_OFF); } else { config.SetPBToken(PBTOKEN_ALL); } return OptIsOk; } /* complex options */ std::string varkey, varvar; std::string::size_type varkey_end = var.find(':'); if (varkey_end != std::string::npos) { varkey = var.substr(0, varkey_end); varvar = var.substr(varkey_end+1); /* * Directory Aliases */ if (varkey == "diralias") { config.AddDirAlias(varvar, val); return OptIsOk; } } /* * Unknown option */ PrintError(var, "Unknown option. Try fetching the Docs :-)"); OptIsOk = FALSE; return OptIsOk; } BOOL ZMWSConfFileParser::MimeApplyVar(ZMWSMIME& mime_manager, const std::string& var, const std::string& val) { if (var=="ZMWSMIMEDEFAULT") mime_manager.setDefaultMimeType(val); else mime_manager.addMimeType(var, val); print_dbg(("Added MIME Type "+val+" for ."+var+" extension.\n").c_str()); return TRUE; } BOOL ZMWSConfFileParser::HandlerApplyVar(ZMWSConfig& config, const std::string& var, const std::string& val) { ZMWSHandler handler; handler.handlerType = handler.DEFAULT; handler.handlerPath += val; config.AddHandler(var, handler); print_dbg(("Added Handler "+val+" for ."+var+" extension.\n").c_str()); return TRUE; } BOOL ZMWSConfFileParser::TRUECGIHandlerApplyVar(ZMWSConfig& config, const std::string& var, const std::string& val) { ZMWSHandler handler; handler.handlerType = handler.TRUECGI; handler.handlerPath = val; config.AddHandler(var, handler); print_dbg(("Added True CGI Handler "+val+" for ."+var+" extension.\n").c_str()); return TRUE; } BOOL ZMWSConfFileParser::ZMWSSAPIHandlerApplyVar(ZMWSConfig& config, const std::string& var, const std::string& val) { ZMWSHandler handler; handler.handlerType = handler.ZMWSSAPI; handler.handlerPath = val; config.AddHandler(var, handler); print_dbg(("Added ZMWS SAPI Handler "+val+" for ."+var+" extension.\n").c_str()); return TRUE; }