LEFT | RIGHT |
(no file at all) | |
1 #include "PluginStdAfx.h" | |
2 | |
3 #include "PluginIniFile.h" | |
4 #include "PluginChecksum.h" | |
5 #include "PluginHttpRequest.h" | |
6 #include "PluginClient.h" | |
7 #include "PluginSettings.h" | |
8 #include "PluginSystem.h" | |
9 #include "config.h" | |
10 | |
11 #include <winhttp.h> | |
12 | |
13 | |
14 //class to ensure that HInternet always is closed | |
15 class HINTERNETHandle | |
16 { | |
17 | |
18 private: | |
19 | |
20 HINTERNET m_handle; | |
21 | |
22 public: | |
23 | |
24 HINTERNETHandle() : m_handle(NULL) {} | |
25 | |
26 HINTERNETHandle(HINTERNET hInternet) : m_handle(hInternet) {} | |
27 | |
28 HINTERNETHandle(HINTERNETHandle& handle) | |
29 { | |
30 m_handle = handle.m_handle; | |
31 handle.m_handle = NULL; | |
32 } | |
33 | |
34 HINTERNETHandle& operator=(HINTERNET hInternet) | |
35 { | |
36 assert(!m_handle); | |
37 m_handle = hInternet; | |
38 return *this; | |
39 } | |
40 | |
41 HINTERNET operator*() | |
42 { | |
43 return m_handle; | |
44 } | |
45 | |
46 ~HINTERNETHandle() | |
47 { | |
48 // close the handle | |
49 if (m_handle) | |
50 { | |
51 if (!::WinHttpCloseHandle(m_handle)) | |
52 { | |
53 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP, PLUGIN_ERROR_HTTP_C
LOSE_HANDLE, "Http::~HINTERNETHandle - WinHttpCloseHandle") | |
54 } | |
55 } | |
56 } | |
57 }; | |
58 | |
59 | |
60 CPluginHttpRequest::CPluginHttpRequest(const CString& script, bool addChecksum)
: | |
61 m_script(script), m_urlPrefix("?"), m_addChecksum(addChecksum) | |
62 { | |
63 m_checksum = std::auto_ptr<CPluginChecksum>(new CPluginChecksum()); | |
64 m_checksum->Add(script); | |
65 | |
66 m_responseFile = std::auto_ptr<CPluginIniFile>(new CPluginIniFile("", true)); | |
67 | |
68 m_url = CString(USERS_PATH) + script; | |
69 } | |
70 | |
71 | |
72 CPluginHttpRequest::~CPluginHttpRequest() | |
73 { | |
74 } | |
75 | |
76 | |
77 void CPluginHttpRequest::AddPluginId() | |
78 { | |
79 CPluginSettings* settings = CPluginSettings::GetInstance(); | |
80 | |
81 CPluginSystem* system = CPluginSystem::GetInstance(); | |
82 | |
83 Add("version", IEPLUGIN_VERSION); | |
84 } | |
85 | |
86 void CPluginHttpRequest::AddOsInfo() | |
87 { | |
88 DWORD osVersion = ::GetVersion(); | |
89 | |
90 Add("os1", (LOBYTE(LOWORD(osVersion)))); | |
91 Add("os2", (HIBYTE(LOWORD(osVersion)))); | |
92 } | |
93 | |
94 bool CPluginHttpRequest::Send(bool checkResponse) | |
95 { | |
96 if (m_addChecksum) | |
97 { | |
98 m_url += m_urlPrefix + "checksum=" + m_checksum->GetAsString(); | |
99 | |
100 m_urlPrefix = "&"; | |
101 } | |
102 | |
103 DEBUG_GENERAL("*** Sending HTTP request:" + m_url) | |
104 | |
105 bool isOk = SendHttpRequest(USERS_HOST, m_url, &m_responseText, USERS_PORT)
? true:false; | |
106 if (isOk && checkResponse) | |
107 { | |
108 isOk = IsValidResponse(); | |
109 } | |
110 | |
111 return isOk; | |
112 } | |
113 | |
114 void CPluginHttpRequest::Add(const CString& arg, const CString& value, bool addT
oChecksum) | |
115 { | |
116 if (!arg.IsEmpty() && !value.IsEmpty()) | |
117 { | |
118 CString valueEncoded; | |
119 DWORD cb = 2048; | |
120 | |
121 HRESULT hr = ::UrlEscape(value, valueEncoded.GetBufferSetLength(cb), &cb, UR
L_ESCAPE_SEGMENT_ONLY); | |
122 if (SUCCEEDED(hr)) | |
123 { | |
124 valueEncoded.Truncate(cb); | |
125 } | |
126 else | |
127 { | |
128 valueEncoded = value; | |
129 | |
130 DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ERROR_HTTP_REQUEST_U
RL_ESCAPE, "HttpRequest::Add - UrlEscape failed on " + value) | |
131 } | |
132 | |
133 m_url += m_urlPrefix + arg + "=" + valueEncoded; | |
134 | |
135 if (addToChecksum) | |
136 { | |
137 m_checksum->Add(arg); | |
138 m_checksum->Add(valueEncoded); | |
139 } | |
140 | |
141 m_urlPrefix = "&"; | |
142 } | |
143 } | |
144 | |
145 void CPluginHttpRequest::Add(const CString& arg, unsigned int value, bool addToC
hecksum) | |
146 { | |
147 CString valueStr; | |
148 valueStr.Format(L"%u", value); | |
149 | |
150 Add(arg, valueStr, addToChecksum); | |
151 } | |
152 | |
153 CString CPluginHttpRequest::GetUrl() | |
154 { | |
155 if (m_addChecksum) | |
156 { | |
157 m_url += m_urlPrefix + "checksum=" + m_checksum->GetAsString(); | |
158 m_urlPrefix = "&"; | |
159 } | |
160 | |
161 return CString(USERS_HOST) + m_url; | |
162 } | |
163 | |
164 | |
165 CString CPluginHttpRequest::GetStandardUrl(const CString& script) | |
166 { | |
167 CPluginHttpRequest httpRequest(script); | |
168 | |
169 httpRequest.AddPluginId(); | |
170 | |
171 return httpRequest.GetUrl(); | |
172 } | |
173 | |
174 | |
175 CStringA CPluginHttpRequest::GetResponseText() const | |
176 { | |
177 return m_responseText; | |
178 } | |
179 | |
180 const std::auto_ptr<CPluginIniFile>& CPluginHttpRequest::GetResponseFile() const | |
181 { | |
182 return m_responseFile; | |
183 } | |
184 | |
185 bool CPluginHttpRequest::IsValidResponse() const | |
186 { | |
187 m_responseFile->Clear(); | |
188 m_responseFile->SetInitialChecksumString(m_script); | |
189 | |
190 bool isValidResponse = m_responseFile->ReadString(m_responseText); | |
191 if (isValidResponse) | |
192 { | |
193 CPluginIniFile::TSectionData status = m_responseFile->GetSectionData(_T("Sta
tus")); | |
194 CPluginIniFile::TSectionData::iterator it; | |
195 | |
196 it = status.find(_T("status")); | |
197 if (it != status.end()) | |
198 { | |
199 isValidResponse = (it->second == "OK"); | |
200 } | |
201 else | |
202 { | |
203 isValidResponse = false; | |
204 } | |
205 } | |
206 | |
207 return isValidResponse; | |
208 } | |
209 | |
210 BOOL CPluginHttpRequest::GetProxySettings(CString& proxyName, CString& proxyBypa
ss) | |
211 { | |
212 BOOL bResult = TRUE; | |
213 | |
214 proxyName.Empty(); | |
215 proxyBypass.Empty(); | |
216 | |
217 // Get Proxy config info. | |
218 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig; | |
219 | |
220 ::ZeroMemory(&proxyConfig, sizeof(proxyConfig)); | |
221 | |
222 if (::WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig)) | |
223 { | |
224 proxyName = proxyConfig.lpszProxy; | |
225 proxyBypass = proxyConfig.lpszProxyBypass; | |
226 } | |
227 else | |
228 { | |
229 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP, PLUGIN_ERROR_HTTP_PROXY
_SETTINGS, "Http::GetProxySettings - WinHttpGetIEProxyConfigForCurrentUser")
| |
230 bResult = FALSE; | |
231 } | |
232 | |
233 // The strings need to be freed. | |
234 if (proxyConfig.lpszProxy != NULL) | |
235 { | |
236 ::GlobalFree(proxyConfig.lpszProxy); | |
237 } | |
238 if (proxyConfig.lpszAutoConfigUrl != NULL) | |
239 { | |
240 ::GlobalFree(proxyConfig.lpszAutoConfigUrl); | |
241 } | |
242 if (proxyConfig.lpszProxyBypass!= NULL) | |
243 { | |
244 ::GlobalFree(proxyConfig.lpszProxyBypass); | |
245 } | |
246 | |
247 return bResult; | |
248 } | |
249 | |
250 bool CPluginHttpRequest::SendHttpRequest(LPCWSTR server, LPCWSTR file, CStringA*
response, WORD nServerPort) | |
251 { | |
252 // Prepare url | |
253 DWORD cb = 2049; | |
254 CString url; | |
255 HRESULT hr = ::UrlCanonicalize(file, url.GetBufferSetLength(cb), &cb, URL_ESCA
PE_UNSAFE); | |
256 if (FAILED(hr)) | |
257 { | |
258 DEBUG_ERROR_CODE(hr, "HttpRequest::SendHttpRequest::UrlCanonicalize failed o
n " + CString(file)) | |
259 return false; | |
260 } | |
261 | |
262 DWORD dwSize = 0; | |
263 DWORD dwDownloaded = 0; | |
264 bool bResult = false; | |
265 HINTERNETHandle hSession, hConnect, hRequest; | |
266 | |
267 // Get Proxy config info. | |
268 CString proxyName; | |
269 CString proxyBypass; | |
270 | |
271 CPluginHttpRequest::GetProxySettings(proxyName, proxyBypass); | |
272 | |
273 // If there is is proxy setting, use it. | |
274 if (proxyName.IsEmpty()) | |
275 { | |
276 hSession = ::WinHttpOpen(BHO_NAME, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTT
P_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); | |
277 } | |
278 // Use WinHttpOpen to obtain a session handle. | |
279 else | |
280 { | |
281 hSession = ::WinHttpOpen(BHO_NAME, WINHTTP_ACCESS_TYPE_NAMED_PROXY, proxyNam
e, proxyBypass, 0); | |
282 } | |
283 | |
284 // Specify an HTTP server. | |
285 if (*hSession) | |
286 { | |
287 hConnect = ::WinHttpConnect(*hSession, server, nServerPort, 0); | |
288 } | |
289 else | |
290 { | |
291 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ERROR_HT
TP_REQUEST_OPEN, "HttpRequest::SendHttpRequest - WinHttpOpen") | |
292 } | |
293 | |
294 // Create an HTTP request handle. | |
295 if (*hConnect) | |
296 { | |
297 DWORD dwFlags = 0; | |
298 if (nServerPort == INTERNET_DEFAULT_HTTPS_PORT) | |
299 { | |
300 dwFlags = WINHTTP_FLAG_SECURE; | |
301 } | |
302 | |
303 hRequest = ::WinHttpOpenRequest(*hConnect, L"GET", url, NULL, WINHTTP_NO_REF
ERER, WINHTTP_DEFAULT_ACCEPT_TYPES, dwFlags); | |
304 } | |
305 else | |
306 { | |
307 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ERROR_HT
TP_REQUEST_CONNECT, "HttpRequest::SendHttpRequest - WinHttpConnect") | |
308 } | |
309 | |
310 // close the url, wont be needed anymore | |
311 url.ReleaseBuffer(); | |
312 | |
313 // Send a request. | |
314 if (*hRequest) | |
315 { | |
316 HTTP_VERSION_INFO ver; | |
317 DWORD l = sizeof(ver); | |
318 WinHttpQueryOption(NULL, WINHTTP_OPTION_HTTP_VERSION, (void*)&ver, &l); | |
319 if (ver.dwMinorVersion == 1) | |
320 { | |
321 bResult = ::WinHttpSendRequest(*hRequest, L"Accept-Encoding: gzip, deflate
", 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0) ? true : false; | |
322 } | |
323 else | |
324 { | |
325 bResult = ::WinHttpSendRequest(*hRequest, L"", 0, WINHTTP_NO_REQUEST_DATA,
0, 0, 0) ? true : false; | |
326 } | |
327 if (!bResult) | |
328 { | |
329 DWORD dwError = ::GetLastError(); | |
330 | |
331 if (dwError == 12007L) // ERROR_INTERNET_NAME_NOT_RESOLVED | |
332 { | |
333 DEBUG_GENERAL("*** Trying to detect proxy for URL") | |
334 | |
335 // Set up the autoproxy call | |
336 WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions; | |
337 WINHTTP_PROXY_INFO proxyInfo; | |
338 DWORD cbProxyInfoSize = sizeof(proxyInfo); | |
339 | |
340 ::ZeroMemory(&autoProxyOptions, sizeof(autoProxyOptions)); | |
341 ::ZeroMemory(&proxyInfo, sizeof(proxyInfo)); | |
342 | |
343 // Use auto-detection because the Proxy | |
344 // Auto-Config URL is not known. | |
345 autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; | |
346 | |
347 // Use DHCP and DNS-based auto-detection. | |
348 autoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WIN
HTTP_AUTO_DETECT_TYPE_DNS_A; | |
349 | |
350 // If obtaining the PAC script requires NTLM/Negotiate | |
351 // authentication, then automatically supply the client | |
352 // domain credentials. | |
353 autoProxyOptions.fAutoLogonIfChallenged = TRUE; | |
354 | |
355 CString completeUrl = (nServerPort == INTERNET_DEFAULT_HTTPS_PORT ? "htt
ps://" : "http://"); | |
356 completeUrl += server; | |
357 completeUrl += file; | |
358 | |
359 bResult = ::WinHttpGetProxyForUrl(*hSession, completeUrl, &autoProxyOpti
ons, &proxyInfo) ? true : false; | |
360 if (bResult) | |
361 { | |
362 bResult = ::WinHttpSetOption(*hRequest, WINHTTP_OPTION_PROXY, &proxyIn
fo, cbProxyInfoSize) ? true : false; | |
363 if (!bResult) | |
364 { | |
365 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_
ERROR_HTTP_REQUEST_SET_OPTION, "HttpRequest::SendHttpRequest - WinHttpSetOption"
) | |
366 } | |
367 } | |
368 else | |
369 { | |
370 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ER
ROR_HTTP_REQUEST_GET_URL_PROXY, "HttpRequest::SendHttpRequest WinHttpGetProxyFor
Url") | |
371 } | |
372 | |
373 if (bResult) | |
374 { | |
375 bResult = ::WinHttpSendRequest(*hRequest, WINHTTP_NO_ADDITIONAL_HEADER
S, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0) ? true : false; | |
376 if (!bResult) | |
377 { | |
378 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_
ERROR_HTTP_REQUEST_SEND_REQUEST, "HttpRequest::SendHttpRequest - WinHttpSendRequ
est") | |
379 } | |
380 } | |
381 } | |
382 else | |
383 { | |
384 DEBUG_ERROR_LOG(dwError, PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ERROR_HTTP_RE
QUEST_SEND_REQUEST, "HttpRequest::SendHttpRequest - WinHttpSendRequest") | |
385 } | |
386 } | |
387 } | |
388 else | |
389 { | |
390 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ERROR_HT
TP_REQUEST_OPEN_REQUEST, "HttpRequest::SendHttpRequest - WinHttpOpenRequest") | |
391 } | |
392 | |
393 // End the request. | |
394 if (bResult) | |
395 { | |
396 bResult = ::WinHttpReceiveResponse(*hRequest, NULL) ? true : false; | |
397 if (!bResult) | |
398 { | |
399 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ERROR_
HTTP_REQUEST_RECEIVE_RESPONSE, "HttpRequest::SendHttpRequest - WinHttpReceiveRes
ponse") | |
400 } | |
401 } | |
402 | |
403 // Keep checking for data until there is nothing left. | |
404 if (bResult) | |
405 { | |
406 //check the header - if we do not receive an ad-aid tag in the header | |
407 //then the answer cannot come from our server, maybe it is from an hotspot o
r something similar | |
408 //that demands validation before access to the internet is granted | |
409 //see http://msdn.microsoft.com/en-us/library/aa384102(VS.85).aspx for docum
entation of queryheaders | |
410 //we look for X-AIDPING: aidonline | |
411 LPCWSTR headerName = L"X-AIDPING"; | |
412 wchar_t lpOutBuffer[50]; | |
413 DWORD dwSize = 50; | |
414 | |
415 if (nServerPort != 80 && ::WinHttpQueryHeaders(*hRequest, WINHTTP_QUERY_CUST
OM, headerName, lpOutBuffer, &dwSize, WINHTTP_NO_HEADER_INDEX)) | |
416 { | |
417 if (CStringW(lpOutBuffer,dwSize) != CStringW(L"aidonline")) | |
418 { | |
419 // Unknown server - we return error | |
420 DEBUG_ERROR_LOG(0, PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ERROR_HTTP_REQUEST_
INVALID_RESPONSE_SERVER, "HttpRequest::SendHttpRequest - Reponse not from correc
t server") | |
421 return false; | |
422 } | |
423 } | |
424 else if (nServerPort != 80) | |
425 { | |
426 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ERROR_
HTTP_REQUEST_QUERY_HEADERS, "HttpRequest::SendHttpRequest - WinHttpQueryHeaders"
) | |
427 } | |
428 | |
429 do | |
430 { | |
431 // Check for available data. | |
432 dwSize = 0; | |
433 if (!::WinHttpQueryDataAvailable(*hRequest, &dwSize)) | |
434 { | |
435 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ERRO
R_HTTP_REQUEST_QUERY_DATA_AVAILABLE, "HttpRequest::SendHttpRequest - WinHttpQuer
yDataAvailable") | |
436 return false; | |
437 } | |
438 | |
439 // Allocate space for the buffer. | |
440 CStringA outBuffer; | |
441 LPVOID pOutBuffer = outBuffer.GetBufferSetLength(dwSize+1); | |
442 if (!pOutBuffer) | |
443 { | |
444 dwSize = 0; | |
445 return false; | |
446 } | |
447 else | |
448 { | |
449 // Read the data. | |
450 ::ZeroMemory(pOutBuffer, dwSize+1); | |
451 | |
452 if (!::WinHttpReadData(*hRequest, pOutBuffer, dwSize, &dwDownloaded)) | |
453 { | |
454 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_HTTP_REQUEST, PLUGIN_ER
ROR_HTTP_REQUEST_READ_DATA, "HttpRequest::SendHttpRequest - WinHttpReadData") | |
455 return false; | |
456 } | |
457 else | |
458 { | |
459 if (response) | |
460 { | |
461 *response += outBuffer; | |
462 } | |
463 } | |
464 | |
465 // Free the memory allocated to the buffer. | |
466 } | |
467 | |
468 outBuffer.ReleaseBuffer(); | |
469 | |
470 } while (dwSize > 0); | |
471 } | |
472 | |
473 return bResult; | |
474 } | |
LEFT | RIGHT |