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 |