| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #include <AdblockPlus.h> | |
| 2 #include <iostream> | |
| 3 #include <ShlObj.h> | |
| 4 #include <sstream> | |
| 5 #include <vector> | |
| 6 #include <Windows.h> | |
| 7 #include <Sddl.h> | |
| 8 | |
| 9 namespace | |
| 10 { | |
| 11 const std::wstring pipeName = L"\\\\.\\pipe\\adblockplusengine"; | |
|
Wladimir Palant
2013/05/23 14:25:01
I realized that the pipe name should be user-speci
Felix Dahlke
2013/05/23 19:10:44
Oh, you're right. Appended the user name. Consider
Wladimir Palant
2013/05/23 20:10:15
Not sure whether the user name can be changed but
| |
| 12 const int bufferSize = 1024; | |
| 13 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine; | |
| 14 | |
| 15 class AutoHandle | |
| 16 { | |
| 17 public: | |
| 18 AutoHandle() | |
| 19 { | |
| 20 } | |
| 21 | |
| 22 AutoHandle(HANDLE handle) : handle(handle) | |
| 23 { | |
| 24 } | |
| 25 | |
| 26 ~AutoHandle() | |
| 27 { | |
| 28 CloseHandle(handle); | |
| 29 } | |
| 30 | |
| 31 HANDLE get() | |
| 32 { | |
| 33 return handle; | |
| 34 } | |
| 35 | |
| 36 private: | |
| 37 HANDLE handle; | |
| 38 | |
| 39 AutoHandle(const AutoHandle& autoHandle); | |
| 40 AutoHandle& operator=(const AutoHandle& autoHandle); | |
| 41 }; | |
| 42 | |
| 43 void Log(const std::string& message) | |
| 44 { | |
| 45 // TODO: Log to a log file | |
| 46 MessageBoxA(0, ("AdblockPlusEngine: " + message).c_str(), "", MB_OK); | |
| 47 } | |
| 48 | |
| 49 void LogLastError(const std::string& message) | |
| 50 { | |
| 51 std::stringstream stream; | |
| 52 stream << message << " (Error code: " << GetLastError() << ")"; | |
| 53 Log(stream.str()); | |
| 54 } | |
| 55 | |
| 56 void LogException(const std::exception& exception) | |
| 57 { | |
| 58 Log(std::string("An exception occurred: ") + exception.what()); | |
| 59 } | |
| 60 | |
| 61 std::string MarshalStrings(const std::vector<std::string>& strings) | |
| 62 { | |
| 63 // TODO: This is some pretty hacky marshalling, replace it with something mo re robust | |
| 64 std::string marshalledStrings; | |
| 65 for (std::vector<std::string>::const_iterator it = strings.begin(); it != st rings.end(); it++) | |
| 66 marshalledStrings += *it + ';'; | |
| 67 return marshalledStrings; | |
| 68 } | |
| 69 | |
| 70 std::vector<std::string> UnmarshalStrings(const std::string& message) | |
| 71 { | |
| 72 std::stringstream stream(message); | |
| 73 std::vector<std::string> strings; | |
| 74 std::string string; | |
| 75 while (std::getline(stream, string, ';')) | |
| 76 strings.push_back(string); | |
| 77 return strings; | |
| 78 } | |
| 79 | |
| 80 std::string ToString(std::wstring value) | |
| 81 { | |
| 82 int size = WideCharToMultiByte(CP_UTF8, 0, value.c_str(), value.length(), 0, 0, 0, 0); | |
|
Wladimir Palant
2013/05/23 14:25:01
Error case (size is 0 for a value with non-zero le
Felix Dahlke
2013/05/23 19:10:44
It is, it returns an empty string. I thought it wa
Wladimir Palant
2013/05/23 20:10:15
We should actually crash early here. While I canno
| |
| 83 std::auto_ptr<char> converted(new char[size]); | |
| 84 WideCharToMultiByte(CP_UTF8, 0, value.c_str(), value.length(), converted.get (), size, 0, 0); | |
| 85 std::string string(converted.get(), size); | |
| 86 return string; | |
| 87 } | |
| 88 | |
| 89 std::string ReadMessage(HANDLE pipe) | |
| 90 { | |
| 91 std::stringstream stream; | |
| 92 std::auto_ptr<char> buffer(new char[bufferSize]); | |
| 93 bool doneReading = false; | |
| 94 while (!doneReading) | |
| 95 { | |
| 96 DWORD bytesRead; | |
| 97 if (ReadFile(pipe, buffer.get(), bufferSize * sizeof(char), &bytesRead, 0) ) | |
| 98 doneReading = true; | |
| 99 else if (GetLastError() != ERROR_MORE_DATA) | |
| 100 { | |
| 101 std::stringstream stream; | |
| 102 stream << "Error reading from pipe: " << GetLastError(); | |
| 103 throw std::runtime_error(stream.str()); | |
| 104 } | |
| 105 stream << std::string(buffer.get(), bytesRead); | |
| 106 } | |
| 107 return stream.str(); | |
| 108 } | |
| 109 | |
| 110 void WriteMessage(HANDLE pipe, const std::string& message) | |
| 111 { | |
| 112 DWORD bytesWritten; | |
| 113 if (!WriteFile(pipe, message.c_str(), message.length(), &bytesWritten, 0)) | |
| 114 throw std::runtime_error("Failed to write to pipe"); | |
| 115 } | |
| 116 | |
| 117 std::string HandleRequest(const std::vector<std::string>& strings) | |
| 118 { | |
| 119 std::string procedureName = strings[0]; | |
| 120 if (procedureName == "Matches") | |
| 121 return filterEngine->Matches(strings[1], strings[2], strings[3]) ? "1" : " 0"; | |
| 122 if (procedureName == "GetElementHidingSelectors") | |
| 123 return MarshalStrings(filterEngine->GetElementHidingSelectors(strings[1])) ; | |
| 124 return ""; | |
| 125 } | |
| 126 | |
| 127 DWORD WINAPI ClientThread(LPVOID param) | |
| 128 { | |
| 129 HANDLE pipe = static_cast<HANDLE>(param); | |
| 130 | |
| 131 try | |
| 132 { | |
| 133 std::string message = ReadMessage(pipe); | |
| 134 std::vector<std::string> strings = UnmarshalStrings(message); | |
| 135 std::string response = HandleRequest(strings); | |
| 136 WriteMessage(pipe, response); | |
| 137 } | |
| 138 catch (const std::exception& e) | |
| 139 { | |
| 140 LogException(e); | |
| 141 } | |
| 142 | |
| 143 // TODO: Keep the pipe open until the client disconnects | |
| 144 FlushFileBuffers(pipe); | |
| 145 DisconnectNamedPipe(pipe); | |
| 146 CloseHandle(pipe); | |
| 147 return 0; | |
| 148 } | |
| 149 | |
| 150 bool IsWindowsVistaOrLater() | |
| 151 { | |
| 152 OSVERSIONINFOEX osvi; | |
| 153 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); | |
| 154 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | |
| 155 GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&osvi)); | |
| 156 return osvi.dwMajorVersion >= 6; | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 std::wstring GetAppDataPath() | |
| 161 { | |
| 162 std::wstring appDataPath; | |
| 163 if (IsWindowsVistaOrLater()) | |
| 164 { | |
| 165 WCHAR* pathBuffer; | |
| 166 if (FAILED(SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0, 0, &pathBuffer) )) | |
| 167 throw std::runtime_error("Unable to find app data directory"); | |
| 168 appDataPath.assign(pathBuffer); | |
| 169 CoTaskMemFree(pathBuffer); | |
| 170 } | |
| 171 else | |
| 172 { | |
| 173 std::auto_ptr<wchar_t> pathBuffer(new wchar_t[MAX_PATH]); | |
| 174 if (!SHGetSpecialFolderPath(0, pathBuffer.get(), CSIDL_LOCAL_APPDATA, true)) | |
| 175 throw std::runtime_error("Unable to find app data directory"); | |
| 176 appDataPath.assign(pathBuffer.get()); | |
| 177 } | |
| 178 return std::wstring(appDataPath) + L"\\AdblockPlus"; | |
|
Wladimir Palant
2013/05/23 14:25:01
appDataPath already is a wstring, no need to const
Felix Dahlke
2013/05/23 19:10:44
Done.
| |
| 179 } | |
| 180 | |
| 181 std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine() | |
| 182 { | |
| 183 // TODO: Pass appInfo in, which should be sent by the client | |
| 184 AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::New(); | |
| 185 std::string dataPath = ToString(GetAppDataPath()); | |
| 186 dynamic_cast<AdblockPlus::DefaultFileSystem*>(jsEngine->GetFileSystem().get()) ->SetBasePath(dataPath); | |
| 187 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine(new AdblockPlus::FilterE ngine(jsEngine)); | |
| 188 std::vector<AdblockPlus::SubscriptionPtr> subscriptions = filterEngine->FetchA vailableSubscriptions(); | |
| 189 // TODO: Select a subscription based on the language, not just the first one. | |
| 190 // This should ideally be done in libadblockplus. | |
| 191 AdblockPlus::SubscriptionPtr subscription = subscriptions[0]; | |
| 192 subscription->AddToList(); | |
| 193 return filterEngine; | |
| 194 } | |
| 195 | |
| 196 HANDLE CreatePipe(const std::wstring& pipeName) | |
| 197 { | |
| 198 SECURITY_ATTRIBUTES sa; | |
| 199 memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); | |
| 200 sa.nLength = sizeof(SECURITY_ATTRIBUTES); | |
| 201 | |
| 202 // Low mandatory label. See http://msdn.microsoft.com/en-us/library/bb625958.a spx | |
| 203 LPCWSTR accessControlEntry = L"S:(ML;;NW;;;LW)"; | |
| 204 PSECURITY_DESCRIPTOR securitydescriptor; | |
| 205 ConvertStringSecurityDescriptorToSecurityDescriptor(accessControlEntry, SDDL_R EVISION_1, &securitydescriptor, 0); | |
| 206 | |
| 207 sa.lpSecurityDescriptor = securitydescriptor; | |
| 208 sa.bInheritHandle = TRUE; | |
| 209 | |
| 210 HANDLE pipe = CreateNamedPipe(pipeName.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_ MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, | |
| 211 PIPE_UNLIMITED_INSTANCES, bufferSize, bufferSize , 0, &sa); | |
| 212 LocalFree(securitydescriptor); | |
| 213 return pipe; | |
| 214 } | |
| 215 | |
| 216 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) | |
| 217 { | |
| 218 filterEngine = CreateFilterEngine(); | |
| 219 | |
| 220 for (;;) | |
| 221 { | |
| 222 HANDLE pipe = CreatePipe(pipeName); | |
| 223 if (pipe == INVALID_HANDLE_VALUE) | |
| 224 { | |
| 225 LogLastError("CreateNamedPipe failed"); | |
| 226 return 1; | |
| 227 } | |
| 228 | |
| 229 if (!ConnectNamedPipe(pipe, 0)) | |
| 230 { | |
| 231 LogLastError("Client failed to connect"); | |
| 232 CloseHandle(pipe); | |
| 233 continue; | |
| 234 } | |
| 235 | |
| 236 // TODO: Count established connections, kill the engine when none are left | |
| 237 | |
| 238 AutoHandle thread(CreateThread(0, 0, ClientThread, static_cast<LPVOID>(pipe) , 0, 0)); | |
| 239 if (!thread.get()) | |
| 240 { | |
| 241 LogLastError("CreateThread failed"); | |
| 242 return 1; | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 return 0; | |
| 247 } | |
| OLD | NEW |