/**
*
*/
package org.snova.framework.proxy.spac.filter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import org.arch.config.IniProperties;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snova.framework.config.SnovaConfiguration;
import org.snova.framework.proxy.spac.filter.gfwlist.GFWListRule;
import org.snova.framework.proxy.spac.filter.gfwlist.HostUrlWildcardRule;
import org.snova.framework.proxy.spac.filter.gfwlist.UrlRegexRule;
import org.snova.framework.proxy.spac.filter.gfwlist.UrlWildcardRule;
import org.snova.framework.util.FileManager;
/**
* @author yinqiwen
*
*/
public class GFWList extends SpacFilter
{
protected static Logger logger = LoggerFactory
.getLogger(GFWList.class);
private static GFWList instance = new GFWList();
private ArrayList<GFWListRule> whiteList = new ArrayList<GFWListRule>();
private ArrayList<GFWListRule> blackList = new ArrayList<GFWListRule>();
private GFWList()
{
}
static GFWList getInstacne()
{
return instance;
}
@Override
public boolean filter(HttpRequest req)
{
for (GFWListRule rule : whiteList)
{
if (rule.match(req))
{
return false;
}
}
for (GFWListRule rule : blackList)
{
if (rule.match(req))
{
return true;
}
}
return whiteList.isEmpty() && blackList.isEmpty();
}
public static void loadRules(String rules) throws IOException
{
ArrayList<GFWListRule> w = new ArrayList<GFWListRule>();
ArrayList<GFWListRule> b = new ArrayList<GFWListRule>();
BufferedReader reader = new BufferedReader(new StringReader(rules));
int i = 0;
while (true)
{
String line = reader.readLine();
i++;
if (i == 1)
{
continue;
}
if (null == line)
{
break;
}
line = line.trim();
if(line.length() == 0)
{
continue;
}
if (line.startsWith("!"))
{
continue;
}
if (line.startsWith("@@||"))
{
HostUrlWildcardRule rule = new HostUrlWildcardRule();
rule.init(line.substring(4));
w.add(rule);
}
else if (line.startsWith("||"))
{
HostUrlWildcardRule rule = new HostUrlWildcardRule();
rule.init(line.substring(2));
b.add(rule);
}
else if (line.startsWith("|http"))
{
UrlWildcardRule rule = new UrlWildcardRule();
rule.init(line.substring(1));
b.add(rule);
}
else if (line.startsWith("/") && line.endsWith("/"))
{
UrlRegexRule rule = new UrlRegexRule();
rule.init(line.substring(1, line.length() - 1));
b.add(rule);
}
else
{
HostUrlWildcardRule rule = new HostUrlWildcardRule();
rule.onlyHttp = true;
rule.init(line);
b.add(rule);
}
}
instance.blackList = b;
instance.whiteList = w;
}
public static void generatePAC(String url, String content)
throws IOException
{
String template = "/*\r\n"
+ "* Proxy Auto-Config file generated by autoproxy2pac\r\n"
+ "* Rule source: ${RuleListUrl}\r\n"
+ "* Last update: ${RuleListDate}\r\n" + "*/\r\n"
+ "function FindProxyForURL(url, host) {\r\n"
+ " var ${ProxyVar} = \"${ProxyString}\";\r\n"
+ " var ${DefaultVar} = \"${DefaultString}\";\r\n"
+ " ${CustomCodePre}\r\n" + " ${RulesBegin}\r\n"
+ " ${RuleListCode}\r\n" + " ${RulesEnd}\r\n"
+ " ${CustomCodePost}\r\n" + " return ${DefaultVar};\r\n" + "}";
IniProperties cfg = SnovaConfiguration.getInstance().getIniProperties();
String rulesBegin = "//-- AUTO-GENERATED RULES, DO NOT MODIFY!";
String rulesEnd = "//-- END OF AUTO-GENERATED RULES";
String proxyVar = "PROXY";
String ruleListUrl = url;
String ruleListDate = "";
String proxyString = "PROXY " + cfg.getProperty("SPAC", "PACProxy");
String defaultVar = "DEFAULT";
String defaultString = "DIRECT";
StringBuilder jsCode = new StringBuilder();
BufferedReader reader = new BufferedReader(new StringReader(content));
int i = 0;
while (true)
{
String line = reader.readLine();
i++;
if (i == 1)
{
continue;
}
if (null == line)
{
break;
}
line = line.trim();
// comment
if (line.length() == 0 || line.startsWith("!"))
{
continue;
}
String proxy_var = "PROXY";
if (line.startsWith("@@"))
{
line = line.substring(2);
proxy_var = "DEFAULT";
}
String jsRegexp = "";
if (line.startsWith("/") && line.endsWith("/"))
{
jsRegexp = line.substring(1, line.length() - 1);
}
else
{
jsRegexp = line.replaceAll("\\*+", "*");
jsRegexp = jsRegexp.replaceFirst("\\^\\|$", "^");
jsRegexp = jsRegexp.replaceAll("(\\W)", "\\\\$1");
jsRegexp = jsRegexp.replaceAll("\\\\\\*", ".*");
jsRegexp = jsRegexp.replaceAll("\\\\^",
"(?:[^\\w\\-.%\u0080-\uFFFF]|$)");
jsRegexp = jsRegexp.replaceFirst("^\\\\\\|\\\\\\|",
"^[\\\\w\\\\-]+:\\\\/+(?!\\\\/)(?:[^\\\\/]+\\\\.)?");
jsRegexp = jsRegexp.replaceFirst("^\\\\\\|", "^");
jsRegexp = jsRegexp.replaceFirst("\\\\\\|$", "$");
jsRegexp = jsRegexp.replaceFirst("^(\\.\\*)", "");
jsRegexp = jsRegexp.replaceFirst("(\\.\\*)$", "");
}
if (jsRegexp.length() == 0)
{
logger.error("There is one rule that matches all URL, which is highly *NOT* recommended: "
+ line);
}
String jsLine = String.format("if(/%s/i.test(url)) return %s;",
jsRegexp, proxy_var);
if (proxy_var.equals("DEFAULT"))
{
StringBuilder tmp = new StringBuilder();
tmp.append(jsLine).append("\r\n\t");
tmp.append(jsCode);
jsCode = tmp;
}
else
{
jsCode.append(jsLine).append("\r\n\t");
}
}
try
{
template = template.replace("${RulesBegin}", rulesBegin);
template = template.replace("${RulesEnd}", rulesEnd);
template = template.replace("${RuleListUrl}", ruleListUrl);
template = template.replace("${RuleListDate}", ruleListDate);
template = template.replace("${ProxyVar}", proxyVar);
template = template.replace("${ProxyString}", proxyString);
template = template.replace("${DefaultVar}", defaultVar);
template = template.replace("${DefaultString}", defaultString);
template = template.replace("${CustomCodePre}", "");
template = template.replace("${RuleListCode}", jsCode.toString());
template = template.replace("${CustomCodePost}", "");
}
catch (Exception e)
{
logger.error("Failed to generate PAC.", e);
}
FileManager.writeFile(template, "spac/snova-gfwlist.pac");
}
}