Sync DrDump crash handler with TortoiseSVN codebase
[TortoiseGit.git] / ext / CrashServer / CommonLibs / Stat / stat.cpp
blob9d7a794a36fe4df343a4d755610afb0aaa60f991
1 // Copyright 2014 Idol Software, Inc.
2 //
3 // This file is part of Doctor Dump SDK.
4 //
5 // Doctor Dump SDK is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "stat.h"
19 #include <atlutil.h>
21 namespace wininet
23 class Error: public std::runtime_error
25 static std::string GetError(const char* text, DWORD err);
26 public:
27 Error(const char* text, DWORD err) : std::runtime_error(GetError(text, err)) {}
30 class Handle
32 HINTERNET m_handle;
33 public:
34 Handle(HINTERNET handle = NULL) : m_handle(handle) {}
35 ~Handle() { if (m_handle) InternetCloseHandle(m_handle); }
36 operator HINTERNET() { return m_handle; }
37 operator bool() { return m_handle != NULL; }
40 std::vector<BYTE> ReadFile(HINTERNET hRequest);
42 std::string EscapeString(const std::string& text);
45 using namespace wininet;
47 std::string wininet::Error::GetError(const char* text, DWORD err)
49 char buf[1024];
50 sprintf_s(buf, "%s, error %d", text, err);
51 return buf;
54 std::vector<BYTE> wininet::ReadFile(HINTERNET hRequest)
56 std::vector<BYTE> result;
57 DWORD bytesAvailable;
58 while (InternetQueryDataAvailable(hRequest, &bytesAvailable, 0, 0))
60 size_t cur = result.size();
61 result.resize(cur + bytesAvailable);
62 DWORD bytesRead = 0;
63 bool res = !!InternetReadFile(hRequest, result.data() + cur, bytesAvailable, &bytesRead);
64 result.resize(cur + bytesRead);
65 if (!res || bytesRead == 0)
66 break;
68 return result;
71 std::string wininet::EscapeString(const std::string& text)
73 std::string result;
74 result.resize(text.size() * 3);
75 DWORD size = 0;
76 if (!AtlEscapeUrl(text.c_str(), &result.front(), &size, (DWORD)result.size(), ATL_URL_ENCODE_PERCENT))
78 result.resize(size * 3);
79 if (!AtlEscapeUrl(text.c_str(), &result.front(), &size, (DWORD)result.size(), ATL_URL_ENCODE_PERCENT))
80 throw Error("AtlEscapeUrl failed", 0);
82 result.resize(size - 1);
83 return result;
86 std::vector<BYTE> statistics::HttpPost(LPCTSTR agent, const CUrl& url, LPCTSTR* accept, LPCTSTR hdrs, LPVOID postData, DWORD postDataSize, DWORD& responseCode)
88 Handle hSession(InternetOpen(agent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0));
89 if (!hSession)
90 throw Error("InternetOpen failed", GetLastError());
92 Handle hConnect(InternetConnect(hSession, url.GetHostName(), INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1));
93 if (!hConnect)
94 throw Error("InternetConnect failed", GetLastError());
96 Handle hRequest(HttpOpenRequest(hConnect, _T("POST"), url.GetUrlPath(), NULL, NULL, accept, 0, INTERNET_NO_CALLBACK));
97 if (!hRequest)
98 throw Error("HttpOpenRequest failed", GetLastError());
100 if (!HttpSendRequest(hRequest, hdrs, -1, postData, postDataSize))
101 throw Error("HttpSendRequest failed", GetLastError());
103 DWORD size = sizeof(responseCode);
104 HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &responseCode, &size, NULL);
105 return ReadFile(hRequest);
108 std::vector<BYTE> statistics::HttpPostXWwwFormUrlencoded(LPCTSTR agent, const CUrl& url, LPCTSTR* accept, const Params& query, DWORD& responseCode)
110 LPCTSTR hdrs = _T("Content-Type: application/x-www-form-urlencoded");
112 std::string postData;
113 for each (auto& var in query)
115 if (!postData.empty())
116 postData += "&";
117 postData += EscapeString(var.first) + "=" + EscapeString(var.second);
120 return HttpPost(agent, url, accept, hdrs, (LPVOID)postData.c_str(), (DWORD)postData.size(), responseCode);
123 namespace statistics
125 BOOL IsWow64()
127 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
128 LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
130 BOOL bIsWow64 = FALSE;
132 HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
133 if (NULL != hKernel32)
134 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hKernel32,"IsWow64Process");
136 if (NULL != fnIsWow64Process)
137 fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
139 return bIsWow64;
142 std::string GetMachineGuid()
144 std::string result;
145 HKEY hCryptography;
146 #if defined (_WIN64)
147 DWORD param = 0;
148 #else
149 DWORD param = IsWow64() ? KEY_WOW64_64KEY : 0;
150 #endif
151 if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Cryptography"), 0, KEY_READ|param, &hCryptography))
153 result.resize(1024);
154 DWORD size = (DWORD)result.size();
155 if (ERROR_SUCCESS == RegQueryValueExA(hCryptography, "MachineGuid", NULL, NULL, (LPBYTE)&result.front(), &size))
156 result.resize(size);
157 else
158 result = "unknown";
159 RegCloseKey(hCryptography);
161 return result;
164 std::string GetCurrentProcessVersion()
166 TCHAR path[MAX_PATH];
167 if (!GetModuleFileName(NULL, path, _countof(path)))
168 return "0.0.0.0";
170 std::vector<BYTE> verInfo(GetFileVersionInfoSize(path, NULL));
171 VS_FIXEDFILEINFO* lpFileinfo = NULL;
172 UINT uLen;
173 if (verInfo.empty()
174 || !GetFileVersionInfo(path, 0, static_cast<DWORD>(verInfo.size()), &verInfo[0])
175 || !VerQueryValue(&verInfo[0], _T("\\"), (LPVOID*)&lpFileinfo, &uLen))
176 return "0.0.0.0";
178 char version[128];
179 sprintf_s(version, "%d.%d.%d.%d",
180 HIWORD(lpFileinfo->dwProductVersionMS),
181 LOWORD(lpFileinfo->dwProductVersionMS),
182 HIWORD(lpFileinfo->dwProductVersionLS),
183 LOWORD(lpFileinfo->dwProductVersionLS));
184 return version;
188 bool statistics::SendExceptionToGoogleAnalytics(LPCSTR tid, const std::string& cid, const std::string& appName, const std::string& appVersion, const std::string& exceptionDescr, bool exceptionFatal)
192 CUrl url;
193 #ifdef _DEBUG
194 url.CrackUrl(_T("http://httpbin.org/post"));
195 #else
196 url.CrackUrl(_T("http://www.google-analytics.com/collect"));
197 #endif
198 LPCTSTR accept[]= { _T("*/*"), NULL };
199 Params query;
200 query.emplace_back(Param("v", "1"));
201 query.emplace_back(Param("tid", tid));
202 query.emplace_back(Param("cid", cid));
203 query.emplace_back(Param("t", "exception"));
204 query.emplace_back(Param("an", appName));
205 query.emplace_back(Param("av", appVersion));
206 query.emplace_back(Param("exd", exceptionDescr));
207 query.emplace_back(Param("exf", exceptionFatal ? "1" : "0"));
209 DWORD responseCode = 0;
210 std::vector<BYTE> data = HttpPostXWwwFormUrlencoded(_T("MyAgent"), url, accept, query, responseCode);
211 #ifdef _DEBUG
212 printf("HTTP %d\n", responseCode);
213 data.push_back(0);
214 printf("%s", (LPCSTR)data.data());
215 #endif
216 return true;
218 catch (std::exception& ex)
220 UNREFERENCED_PARAMETER(ex);
221 #ifdef _DEBUG
222 printf("Error: %s\n", ex.what());
223 #endif
224 return false;
228 bool statistics::SendExceptionToGoogleAnalytics(
229 LPCSTR tid,
230 const std::string& appName,
231 const std::string& exceptionDescr,
232 bool exceptionFatal)
234 return SendExceptionToGoogleAnalytics(tid, GetMachineGuid(), appName, GetCurrentProcessVersion(), exceptionDescr, exceptionFatal);