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