Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: AdblockPlusEngine/main.cpp

Issue 10580043: Run a single FilterEngine instance in a separate process (Closed)
Patch Set: Addressed all issues Created May 23, 2013, 12:29 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld