Fixed issue #2495: "Show Reflog" dialog shows empty action for "push" entries
[TortoiseGit.git] / src / TortoiseProc / UpdateDownloader.cpp
blobb38bb2d76f0e5e3550acca4e9484546924c94f1c
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2013-2014 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
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 General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include "UpdateDownloader.h"
21 #include "..\version.h"
22 #include "SysInfo.h"
24 CUpdateDownloader::CUpdateDownloader(HWND hwnd, bool force, UINT msg, CEvent *eventStop)
25 : m_hWnd(hwnd)
26 , m_bForce(force)
27 , m_uiMsg(msg)
28 , m_eventStop(eventStop)
30 OSVERSIONINFOEX inf = {0};
31 BruteforceGetWindowsVersionNumber(inf);
33 m_sWindowsPlatform = (inf.dwPlatformId == VER_PLATFORM_WIN32_NT) ? _T("NT") : _T("");
34 m_sWindowsVersion.Format(L"%ld.%ld", inf.dwMajorVersion, inf.dwMinorVersion);
35 if (inf.wServicePackMajor)
36 m_sWindowsServicePack.Format(L"SP%ld", inf.wServicePackMajor);
38 CString userAgent;
39 userAgent.Format(L"TortoiseGit %s; %s; Windows%s%s %s%s%s", _T(STRFILEVER), _T(TGIT_PLATFORM), m_sWindowsPlatform.IsEmpty() ? _T("") : _T(" "), m_sWindowsPlatform, m_sWindowsVersion, m_sWindowsServicePack.IsEmpty() ? _T("") : _T(" "), m_sWindowsServicePack);
40 hOpenHandle = InternetOpen(userAgent, INTERNET_OPEN_TYPE_PRECONFIG, nullptr, nullptr, 0);
43 CUpdateDownloader::~CUpdateDownloader(void)
45 if (hOpenHandle)
46 InternetCloseHandle(hOpenHandle);
49 void CUpdateDownloader::BruteforceGetWindowsVersionNumber(OSVERSIONINFOEX& osVersionInfo)
51 osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
52 GetVersionEx((OSVERSIONINFO *)&osVersionInfo);
54 ULONGLONG maskConditioMajor = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_LESS);
55 ULONGLONG maskConditioMinor = ::VerSetConditionMask(0, VER_MINORVERSION, VER_LESS);
56 ULONGLONG maskConditioSPMajor = ::VerSetConditionMask(0, VER_SERVICEPACKMAJOR, VER_LESS);
57 while (!::VerifyVersionInfo(&osVersionInfo, VER_MAJORVERSION, maskConditioMajor))
59 ++osVersionInfo.dwMajorVersion;
60 osVersionInfo.dwMinorVersion = 0;
61 osVersionInfo.wServicePackMajor = 0;
62 osVersionInfo.wServicePackMinor = 0;
64 while (!::VerifyVersionInfo(&osVersionInfo, VER_MINORVERSION, maskConditioMinor))
66 ++osVersionInfo.dwMinorVersion;
67 osVersionInfo.wServicePackMajor = 0;
68 osVersionInfo.wServicePackMinor = 0;
70 while (!::VerifyVersionInfo(&osVersionInfo, VER_SERVICEPACKMAJOR, maskConditioSPMajor))
71 ++osVersionInfo.wServicePackMajor;
72 // detection of VER_SERVICEPACKMINOR doesn't work reliably
75 DWORD CUpdateDownloader::DownloadFile(const CString& url, const CString& dest, bool showProgress) const
77 CString hostname;
78 CString urlpath;
79 URL_COMPONENTS urlComponents = {0};
80 urlComponents.dwStructSize = sizeof(urlComponents);
81 urlComponents.lpszHostName = hostname.GetBufferSetLength(INTERNET_MAX_HOST_NAME_LENGTH);
82 urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
83 urlComponents.lpszUrlPath = urlpath.GetBufferSetLength(INTERNET_MAX_PATH_LENGTH);
84 urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
85 if (!InternetCrackUrl(url, url.GetLength(), 0, &urlComponents))
86 return GetLastError();
87 hostname.ReleaseBuffer();
88 urlpath.ReleaseBuffer();
90 if (m_bForce)
91 DeleteUrlCacheEntry(url);
93 BOOL bTrue = TRUE;
94 BOOL enableDecoding = InternetSetOption(hOpenHandle, INTERNET_OPTION_HTTP_DECODING, &bTrue, sizeof(bTrue));
96 bool isHttps = urlComponents.nScheme == INTERNET_SCHEME_HTTPS;
97 HINTERNET hConnectHandle = InternetConnect(hOpenHandle, hostname, urlComponents.nPort, nullptr, nullptr, isHttps ? INTERNET_SCHEME_HTTP : urlComponents.nScheme, 0, 0);
98 if (!hConnectHandle)
100 DWORD err = GetLastError();
101 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Download of %s failed on InternetConnect: %d\n"), url, err);
102 return err;
104 HINTERNET hResourceHandle = HttpOpenRequest(hConnectHandle, nullptr, urlpath, nullptr, nullptr, nullptr, INTERNET_FLAG_KEEP_CONNECTION | (isHttps ? INTERNET_FLAG_SECURE : 0), 0);
105 if (!hResourceHandle)
107 DWORD err = GetLastError();
108 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Download of %s failed on HttpOpenRequest: %d\n"), url, err);
109 InternetCloseHandle(hConnectHandle);
110 return err;
113 if (enableDecoding && SysInfo::Instance().IsVistaOrLater())
114 HttpAddRequestHeaders(hResourceHandle, L"Accept-Encoding: gzip, deflate\r\n", (DWORD)-1, HTTP_ADDREQ_FLAG_ADD);
117 resend:
118 BOOL httpsendrequest = HttpSendRequest(hResourceHandle, nullptr, 0, nullptr, 0);
120 DWORD dwError = InternetErrorDlg(m_hWnd, hResourceHandle, ERROR_SUCCESS, FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, nullptr);
122 if (dwError == ERROR_INTERNET_FORCE_RETRY)
123 goto resend;
124 else if (!httpsendrequest)
126 DWORD err = GetLastError();
127 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Download of %s failed: %d, %d\n"), url, httpsendrequest, err);
128 InternetCloseHandle(hResourceHandle);
129 InternetCloseHandle(hConnectHandle);
130 return err;
134 DWORD contentLength = 0;
136 DWORD length = sizeof(contentLength);
137 HttpQueryInfo(hResourceHandle, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&contentLength, &length, NULL);
140 DWORD statusCode = 0;
141 DWORD length = sizeof(statusCode);
142 if (!HttpQueryInfo(hResourceHandle, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&statusCode, &length, NULL) || statusCode != 200)
144 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Download of %s returned %d\n"), url, statusCode);
145 InternetCloseHandle(hResourceHandle);
146 InternetCloseHandle(hConnectHandle);
147 if (statusCode == 404)
148 return ERROR_FILE_NOT_FOUND;
149 else if (statusCode == 403)
150 return ERROR_ACCESS_DENIED;
151 return (DWORD)INET_E_DOWNLOAD_FAILURE;
155 CFile destinationFile;
156 if (!destinationFile.Open(dest, CFile::modeCreate | CFile::modeWrite))
158 InternetCloseHandle(hResourceHandle);
159 InternetCloseHandle(hConnectHandle);
160 return ERROR_ACCESS_DENIED;
162 DWORD downloadedSum = 0; // sum of bytes downloaded so far
165 DWORD size; // size of the data available
166 if (!InternetQueryDataAvailable(hResourceHandle, &size, 0, 0))
168 DWORD err = GetLastError();
169 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Download of %s failed on InternetQueryDataAvailable: %d\n"), url, err);
170 InternetCloseHandle(hResourceHandle);
171 InternetCloseHandle(hConnectHandle);
172 return err;
175 DWORD downloaded; // size of the downloaded data
176 LPTSTR lpszData = new TCHAR[size + 1];
177 if (!InternetReadFile(hResourceHandle, (LPVOID)lpszData, size, &downloaded))
179 delete[] lpszData;
180 DWORD err = GetLastError();
181 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Download of %s failed on InternetReadFile: %d\n"), url, err);
182 InternetCloseHandle(hResourceHandle);
183 InternetCloseHandle(hConnectHandle);
184 return err;
187 if (downloaded == 0)
189 delete[] lpszData;
190 break;
193 lpszData[downloaded] = '\0';
194 destinationFile.Write(lpszData, downloaded);
195 delete[] lpszData;
197 downloadedSum += downloaded;
199 if (!showProgress)
200 continue;
202 ASSERT(m_uiMsg && m_eventStop);
204 if (contentLength == 0) // got no content-length from webserver
206 DOWNLOADSTATUS downloadStatus = { 0, 1 + 1 }; // + 1 for download of signature file
207 ::SendMessage(m_hWnd, m_uiMsg, 0, reinterpret_cast<LPARAM>(&downloadStatus));
209 else
211 if (downloadedSum > contentLength)
212 downloadedSum = contentLength - 1;
213 DOWNLOADSTATUS downloadStatus = { downloadedSum, contentLength + 1 }; // + 1 for download of signature file
214 ::SendMessage(m_hWnd, m_uiMsg, 0, reinterpret_cast<LPARAM>(&downloadStatus));
217 if (::WaitForSingleObject(*m_eventStop, 0) == WAIT_OBJECT_0)
219 InternetCloseHandle(hResourceHandle);
220 InternetCloseHandle(hConnectHandle);
221 return (DWORD)E_ABORT; // canceled by the user
224 while (true);
225 destinationFile.Close();
226 InternetCloseHandle(hResourceHandle);
227 InternetCloseHandle(hConnectHandle);
228 if (downloadedSum == 0)
230 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Download size of %s was zero.\n"), url);
231 return (DWORD)INET_E_DOWNLOAD_FAILURE;
233 return ERROR_SUCCESS;