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 review issues Created May 23, 2013, 7:10 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
« no previous file with comments | « AdblockPlusEngine/AdblockPlusEngine.vcxproj.filters ('k') | Shared/AdblockPlusClient.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « AdblockPlusEngine/AdblockPlusEngine.vcxproj.filters ('k') | Shared/AdblockPlusClient.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld