From 05b2fd671e04c8c12ee6291461eb9e726e15d9eb Mon Sep 17 00:00:00 2001 From: "Leroy.H.Y" Date: Mon, 18 Nov 2019 19:39:51 +0800 Subject: [PATCH] [add] Added GFW->PAC and QHttpServer #69 Former-commit-id: 8b0aef31e285a484fd248abec1aa5de7cdc33e84 --- .gitmodules | 3 + 3rdparty/qhttpserver | 1 + Build.Counter | 2 +- Qv2ray.pro | 14 ++++ src/QvUtils.hpp | 3 + src/utils/QvGFWPACConverter.cpp | 132 ++++++++++++++++++++++++++++++++ 6 files changed, 154 insertions(+), 1 deletion(-) create mode 160000 3rdparty/qhttpserver create mode 100644 src/utils/QvGFWPACConverter.cpp diff --git a/.gitmodules b/.gitmodules index f04e64e4..f5a5d596 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "3rdparty/qzxing_noTests"] path = 3rdparty/qzxing_noTests url = https://github.com/lhy0403/qzxing_noTests +[submodule "3rdparty/qhttpserver"] + path = 3rdparty/qhttpserver + url = https://github.com/nikhilm/qhttpserver diff --git a/3rdparty/qhttpserver b/3rdparty/qhttpserver new file mode 160000 index 00000000..02a6e717 --- /dev/null +++ b/3rdparty/qhttpserver @@ -0,0 +1 @@ +Subproject commit 02a6e7174b5be76e2c0e74a109817e39a141b9fd diff --git a/Build.Counter b/Build.Counter index e0f6509a..c00f282b 100644 --- a/Build.Counter +++ b/Build.Counter @@ -1 +1 @@ -695 +706 diff --git a/Qv2ray.pro b/Qv2ray.pro index a0723880..cbc17469 100644 --- a/Qv2ray.pro +++ b/Qv2ray.pro @@ -39,6 +39,7 @@ SOURCES += \ src/ui/w_RoutesEditor.cpp \ src/ui/w_SubscriptionEditor.cpp \ src/utils/QObjectMessageProxy.cpp \ + src/utils/QvGFWPACConverter.cpp \ src/utils/QvHTTPRequestHelper.cpp \ src/utils/QvPingModel.cpp \ src/utils/QvRunguard.cpp \ @@ -148,9 +149,22 @@ for(var, $$list($$files("translations/*.ts", true))) { message("Qv2ray will build with" $${replace(EXTRA_TRANSLATIONS, "translations/", "")}) TRANSLATIONS += translations/en-US.ts + message(" ") QMAKE_CXXFLAGS += -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable +message("Adding QHttpServer Support") +message(" --> Adding qhttpserver") +HEADERS += $$PWD/3rdparty/qhttpserver/src/*.h +SOURCES += $$PWD/3rdparty/qhttpserver/src/*.cpp +INCLUDEPATH += 3rdparty/qhttpserver/src/ + +message(" --> Adding http parser") +HEADERS += 3rdparty/qhttpserver/http-parser/http_parser.h +SOURCES += 3rdparty/qhttpserver/http-parser/http_parser.c +INCLUDEPATH += 3rdparty/qhttpserver/http-parser + +message(" ") win32 { message("Configuring for win32 environment") message(" --> Setting up target descriptions") diff --git a/src/QvUtils.hpp b/src/QvUtils.hpp index e95e2664..9892ee65 100644 --- a/src/QvUtils.hpp +++ b/src/QvUtils.hpp @@ -84,6 +84,9 @@ namespace Qv2ray QString FormatBytes(long long bytes); void DeducePossibleFileName(const QString &baseDir, QString *fileName, const QString &extension); + // + // + QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString); } } diff --git a/src/utils/QvGFWPACConverter.cpp b/src/utils/QvGFWPACConverter.cpp new file mode 100644 index 00000000..f1a5a1ed --- /dev/null +++ b/src/utils/QvGFWPACConverter.cpp @@ -0,0 +1,132 @@ +/* ORIGINAL LICENSE: Do What The F*ck You Want To Public License + * AUTHOR: LBYPatrick + * + * MODIFIED BY Leroy.H.Y @lhy0403 re-licenced under GPLv3 + */ + +#include "QvUtils.hpp" + +namespace Qv2ray +{ + namespace Utils + { + // Private function + string getRawDomain(string originLine) + { + size_t startPosition = 0; + size_t endPosition = originLine.size(); + string returnBuffer; + bool skipRule1 = originLine.find("[") != string::npos; // [Auto xxxx... + bool skipRule2 = originLine.find("!") != string::npos; // Comments + bool skipRule3 = originLine.find("@") != string::npos; // Non-proxy Lines + bool skipRule4 = originLine.find("*") != string::npos; + bool passRule1 = originLine.find("|") != string::npos; // Proxy Lines + bool passRule2 = originLine.find(".") != string::npos; // Link-Contained Lines + + if (originLine[endPosition] == '\n') { + endPosition -= 1; + } + + if (originLine.find("http://") != string::npos) { + startPosition += 8; + } else if (originLine.find("https://") != string::npos) { + startPosition += 9; + } + + // Skip unrelated lines + if (skipRule1 || skipRule2 || skipRule3 || skipRule4) { + return ""; + } else if (passRule2) { + if (passRule1) { + startPosition += originLine.find_last_of("|") + 1; + } + + if (originLine[startPosition] == '\n') startPosition += 1; + + for (size_t i = startPosition; i < endPosition; ++i) { + returnBuffer += originLine[i]; + } + } + + return returnBuffer; + } + + QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString) + { + auto rawFileContent = Base64Decode(rawContent).toStdString(); + string readBuffer = ""; //cleanup + string writeBuffer; + string domainListCache = ""; + + for (size_t i = 0; i < rawFileContent.size(); ++i) { + readBuffer += rawFileContent[i]; + + if (rawFileContent[i + 1] == '\n') { + writeBuffer = getRawDomain(readBuffer); + + if (writeBuffer != "") { + domainListCache += writeBuffer + "\n"; + } + + readBuffer = ""; + i += 1; + } + } + + size_t rotatorTwo = 0; + string readDomainBuffer = ""; + bool isFirstLine = true; + string outputContent = ""; + //Header + outputContent += "var domains = {\n"; + + //Read and process output content line by line + while (rotatorTwo < domainListCache.size()) { + while (true) { + //Get Domain + readDomainBuffer += domainListCache[rotatorTwo]; + + if (domainListCache[rotatorTwo + 1] == '\n') { + rotatorTwo += 2; + break; + } + + rotatorTwo++; + } + + //Format + if (!isFirstLine) outputContent += ",\n"; + else isFirstLine = false; + + outputContent += "\t\""; + outputContent += readDomainBuffer; + outputContent += "\" : 1"; + readDomainBuffer = ""; + } + + //End Message + outputContent += "\n\n};\n\n\n"; + outputContent += "var proxy = \""; + outputContent += customProxyString.toStdString(); + outputContent += "\";\n"; + outputContent += "var direct = 'DIRECT;';\n"; + outputContent += "var hasOwnProperty = Object.hasOwnProperty;\n\n"; + outputContent += "function FindProxyForURL(url, host) {\n\n"; + outputContent += "\tvar suffix;\n"; + outputContent += "\tvar pos = host.lastIndexOf('.');\n"; + outputContent += "\tpos = host.lastIndexOf('.', pos - 1);\n\n"; + outputContent += "\twhile(1) {\n"; + outputContent += "\t\tif (pos <= 0) {\n"; + outputContent += "\t\t\tif (hasOwnProperty.call(domains, host)) "; + outputContent += "return proxy;\n"; + outputContent += "\t\t\telse "; + outputContent += "return direct;\n"; + outputContent += "\t\t}\n\n"; + outputContent += "\tsuffix = host.substring(pos + 1);\n"; + outputContent += "\tif (hasOwnProperty.call(domains, suffix))"; + outputContent += "return proxy;\n"; + outputContent += "\tpos = host.lastIndexOf('.', pos - 1);\n\t}\n}"; + return QSTRING(outputContent); + } + } +}