package org.hyperic.hq.plugin.apache;
import edu.emory.mathcs.backport.java.util.Arrays;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.product.PluginException;
/**
*
* @author administrator
*/
public class ApacheConf {
private String config;
private static final Pattern virtualHostPatter = Pattern.compile("<VirtualHost ([^>]*)>", Pattern.CASE_INSENSITIVE);
private static final Pattern serverNamePatter = Pattern.compile("ServerName (.*)", Pattern.CASE_INSENSITIVE);
private static final Pattern serverRootPatter = Pattern.compile("ServerRoot \"?([^\\s|\"]*)\"?", Pattern.CASE_INSENSITIVE);
private static final Pattern includePatter = Pattern.compile("Include (.*)", Pattern.CASE_INSENSITIVE);
private static final Pattern ipPattern = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}", Pattern.CASE_INSENSITIVE);
private static final Log log = LogFactory.getLog(ApacheConf.class);
public ApacheConf(File configFile) throws PluginException {
try {
config = readFile(configFile);
File serverRoot = findServerRoot(config);
config = replaceIncludes(config, serverRoot);
} catch (IOException ex) {
throw new PluginException(ex.getMessage(), ex);
}
}
public Map<String, ApacheVHost> getVHosts() throws PluginException, IOException {
Map<String, ApacheVHost> vHosts = new HashMap<String, ApacheVHost>();
int idx = 0;
while ((idx = config.indexOf("<VirtualHost", idx)) > 0) {
int idxEnd = config.indexOf("</VirtualHost>", idx);
vHosts.putAll(parseVirtualHost(config.substring(idx, idxEnd)));
idx=idxEnd;
}
return vHosts;
}
public static Map<String, ApacheVHost> parseVirtualHost(String vhTag) {
Map<String, ApacheVHost> vHost = new HashMap<String, ApacheVHost>();
Matcher mach = virtualHostPatter.matcher(vhTag);
if (mach.find()) {
String addrs = mach.group(1);
String serverName = getServerName(vhTag);
List<String> addrsList = Arrays.asList(addrs.split(" "));
for (String listen : addrsList) {
ApacheListen l = parseListen(listen);
ApacheVHost vh = new ApacheVHost(l.getName(), l.getIp(), l.getPort(), serverName);
log.debug("[getVHosts] vHost=" + vh + " (" + l + ")");
vHost.put(vh.getServerName(), vh);
}
}
return vHost;
}
public static ApacheListen parseListen(String l) {
String ip = null, name = null, port = null;
if (l.contains(":")) {
String comp[] = l.split(":");
String ipName = comp[0];
port = comp[1];
Matcher m = ipPattern.matcher(ipName);
if (m.matches()) {
ip = ipName;
name = getHostAddress(ipName);
} else {
ip = getAddress(ipName);
name = ipName;
}
} else {
port = l;
}
ApacheListen listen = new ApacheListen(name, ip, port);
return listen;
}
private static File findServerRoot(String config) throws PluginException {
File sr = null;
Matcher match = serverRootPatter.matcher(config);
while (match.find() && sr == null) {
log.debug("[findServerRoot] " + match.group());
sr = new File(match.group(1));
if (!(sr.exists() && sr.isDirectory())) {
sr = null;
}
}
if (sr == null) {
throw new PluginException("Direcive 'ServerRoot' not found");
}
return sr;
}
private static String getServerName(String txt) {
String serverName = "";
Matcher m = serverNamePatter.matcher(txt);
while (m.find()) {
serverName = m.group(1).trim();
}
return serverName;
}
private static String replaceIncludes(String config, File serverRoot) throws IOException {
Matcher mach = includePatter.matcher(config);
StringBuffer newConf = new StringBuffer();
while (mach.find()) {
log.debug("[replaceIncludes] found:'" + mach.group() + "'");
String found = mach.group(1);
String pattern = null;
if (isFnmatch(found)) {
int idx = found.lastIndexOf("/");
pattern = found.substring(idx + 1);
found = found.substring(0, idx);
}
File cf = new File(found);
if (!cf.isAbsolute()) {
cf = new File(serverRoot, found);
}
if (cf.exists()) {
if (cf.isFile()) {
log.debug("[replaceIncludes] Including file: '" + cf + "'");
String includeConfig = readFile(cf);
includeConfig = Matcher.quoteReplacement(includeConfig);
String replace = replaceIncludes(includeConfig, serverRoot);
mach.appendReplacement(newConf, replace);
}
if (cf.isDirectory()) {
List<File> files = listFiles(cf);
log.debug("[replaceIncludes] Browsing directory: '" + cf + "' (" + files.size() + " files)");
StringBuilder replace = new StringBuilder();
for (File file : files) {
if ((pattern == null) || fnmatch(pattern, file.getName())) {
log.debug("[replaceIncludes] Including file: '" + file + "'");
String includeConfig = readFile(file);
includeConfig = Matcher.quoteReplacement(includeConfig);
replace.append(replaceIncludes(includeConfig, serverRoot));
} else {
log.debug("[replaceIncludes] Ignoring file: '" + file + "' pattern='" + pattern + "'");
}
}
mach.appendReplacement(newConf, replace.toString());
}
} else {
log.debug("[replaceIncludes] File Not Found!! '" + cf + "'");
}
}
mach.appendTail(newConf);
return newConf.toString();
}
private static List<File> listFiles(File dir) {
List<File> files = new ArrayList<File>();
File ls[] = dir.listFiles();
for (File file : ls) {
if (file.isDirectory()) {
files.addAll(listFiles(file));
} else {
files.add(file);
}
}
return files;
}
private static boolean isFnmatch(String pattern) {
if (pattern.contains("*") || pattern.contains("*")) {
return true;
} else if (pattern.contains("[") || pattern.contains("]")) {
return true;
} else if (pattern.contains("\\") && !pattern.endsWith("\\")) {
return true;
} else {
return false;
}
}
public static boolean fnmatch(String pattern, String filename) {
if (filename.startsWith(".") && !pattern.startsWith(".")) {
return false;
}
if (filename.contains("/.") && !pattern.contains("/.")) {
return false;
}
pattern = pattern.replace("?", ".");
pattern = pattern.replace("*", ".*");
pattern = pattern.replaceAll("\\\\(\\w)", "$1");
pattern = pattern.replace("[!", "[^");
Pattern p;
try {
p = Pattern.compile(pattern + "$");
} catch (PatternSyntaxException ex) {
log.debug(ex, ex);
return false;
}
Matcher m = p.matcher(filename);
return m.matches();
}
private static String readFile(File file) throws IOException {
final char[] buffer = new char[0x10000];
StringBuilder out = new StringBuilder();
BufferedReader in = new BufferedReader(new FileReader(file));
String line;
while ((line = in.readLine()) != null) {
line = line.trim();
if (!line.startsWith("#") && line.length() > 0) {
out.append(line).append('\n');
}
}
return out.toString();
}
private static String getHostAddress(String ip) {
try {
return InetAddress.getByAddress(getIpAsArrayOfByte(ip)).getHostName();
} catch (UnknownHostException ex) {
return ex.toString();
}
}
private static String getAddress(String name) {
try {
return getIpAsString(InetAddress.getByName(name).getAddress());
} catch (UnknownHostException ex) {
return ex.toString();
}
}
private static String getIpAsString(byte[] rawBytes) {
int i = 4;
StringBuilder ipAddress = new StringBuilder();
for (byte raw : rawBytes) {
ipAddress.append(raw & 0xFF);
if (--i > 0) {
ipAddress.append(".");
}
}
return ipAddress.toString();
}
private static byte[] getIpAsArrayOfByte(String ipAddress) {
StringTokenizer st = new StringTokenizer(ipAddress, ".");
byte[] ip = new byte[4];
int i = 0;
while (st.hasMoreTokens()) {
ip[i++] = (byte) Integer.parseInt(st.nextToken());
}
return ip;
}
}