comparison ui/downloader_win.cpp @ 11:7e2f14c7aba2

Split up downloader component and further implement it
author Andre Heinecke <aheinecke@intevation.de>
date Fri, 14 Feb 2014 11:20:15 +0000
parents
children 95e1b6edf2fc
comparison
equal deleted inserted replaced
10:fe39d93f1261 11:7e2f14c7aba2
1 /**
2 * @file downloader_win.cpp
3 * @brief Downloader implementation for Windows
4 *
5 * We use Windows API here instead of Qt because we want to avoid
6 * QtNetworks SSL stack which is based on OpenSSL and so
7 * we might be incompatible with GPL code. Also using the
8 * native API means that the security of the SSL implementation
9 * is tied to the security of the system.
10 *
11 */
12 #include "downloader.h"
13 #ifdef Q_OS_WIN
14 #ifndef MYVERSION
15 #define MYVERSION "1"
16 #endif
17
18 #include <windows.h>
19 #include <winhttp.h>
20
21 #include <QDebug>
22
23 #define DEBUG if (1) qDebug() << __PRETTY_FUNCTION__
24
25 const QString getLastErrorMsg() {
26 LPWSTR bufPtr = NULL;
27 DWORD err = GetLastError();
28 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
29 FORMAT_MESSAGE_FROM_SYSTEM |
30 FORMAT_MESSAGE_IGNORE_INSERTS,
31 NULL, err, 0, (LPWSTR)&bufPtr, 0, NULL);
32 const QString result =
33 (bufPtr) ? QString::fromUtf16((const ushort*)bufPtr).trimmed() :
34 QString("Unknown Error %1").arg(err);
35 LocalFree(bufPtr);
36 return result;
37 }
38
39 /** @brief open a session with appropiate proxy settings
40 *
41 * @param[inout] *pHSession pointer to a HInternet structure
42 *
43 * On error call getLastError to get extended error information.
44 *
45 * @returns True on success, false on error.
46 */
47
48
49 bool openSession(HINTERNET *pHSession)
50 {
51 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig;
52
53 DEBUG;
54 if (!pHSession) {
55 SetLastError(ERROR_INVALID_PARAMETER);
56 return false;
57 }
58
59 qDebug() << "2";
60 memset(&proxyConfig, 0, sizeof (WINHTTP_CURRENT_USER_IE_PROXY_CONFIG));
61
62 if (WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig)) {
63 if (proxyConfig.fAutoDetect) {
64 // TODO Handle this
65 qDebug() << "Autodetect is set";
66 }
67
68 if (proxyConfig.lpszProxy || proxyConfig.lpszProxyBypass) {
69 DEBUG << "Using proxies.";
70 }
71
72 if (proxyConfig.lpszProxy) {
73 *pHSession = WinHttpOpen(L"M13 "MYVERSION,
74 WINHTTP_ACCESS_TYPE_NAMED_PROXY,
75 proxyConfig.lpszProxy,
76 proxyConfig.lpszProxyBypass, 0);
77 }
78 }
79
80 if (!*pHSession) {
81 DEBUG << "No IE Proxy falling back to default proxy";
82 *pHSession = WinHttpOpen(L"M13 "MYVERSION,
83 WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
84 WINHTTP_NO_PROXY_NAME,
85 WINHTTP_NO_PROXY_BYPASS, 0);
86 }
87 // Cleanup
88 if (proxyConfig.lpszAutoConfigUrl) {
89 GlobalFree(proxyConfig.lpszAutoConfigUrl);
90 }
91
92 if (proxyConfig.lpszProxy) {
93 GlobalFree(proxyConfig.lpszProxy);
94 }
95
96 if (proxyConfig.lpszProxyBypass) {
97 GlobalFree(proxyConfig.lpszProxyBypass);
98 }
99 return *pHSession;
100 }
101
102
103 /** @brief initialize a connection in the session
104 *
105 * @param[in] HSession the session to work in.
106 * @param[inout] *pHConnect pointer to the connection.
107 * @param[in] url pointer to the URL in wchar representation.
108 *
109 * On error call getLastError to get extended error information.
110 *
111 * @returns True on success, false on error.
112 */
113 bool initializeConnection(HINTERNET hSession, HINTERNET *pHConnect,
114 LPCWSTR url)
115 {
116 DEBUG;
117 if (!hSession || !pHConnect) {
118 SetLastError(ERROR_INVALID_PARAMETER);
119 return false;
120 }
121 // Initialize connection. No request is done here.
122 *pHConnect = WinHttpConnect(hSession, url,
123 INTERNET_DEFAULT_HTTPS_PORT, 0);
124
125 return *pHConnect;
126 }
127
128 /** @brief Create a request
129 *
130 * @param[in] HSession the session to work in.
131 * @param[in] HConnect the connection to use.
132 * @param[inout] *pHRequest pointer to the request structure to be filled.
133 * @param[in] requestType the HTTP request to be made default is GET
134 * @param[in] resource pointer to the resource to request in wchar
135 * representation.
136 *
137 * On error call getLastError to get extended error information.
138 * This function still does not do any networking but only initializes
139 * it.
140 *
141 * @returns True on success, false on error.
142 */
143
144 bool createRequest(HINTERNET hSession, HINTERNET hConnect,
145 HINTERNET *pHRequest, LPCWSTR requestType, LPCWSTR resource)
146 {
147 DEBUG;
148 if (!hSession || !hConnect || !pHRequest) {
149 SetLastError(ERROR_INVALID_PARAMETER);
150 return false;
151 }
152
153 *pHRequest = WinHttpOpenRequest(hConnect, requestType, resource,
154 NULL, WINHTTP_NO_REFERER,
155 WINHTTP_DEFAULT_ACCEPT_TYPES,
156 WINHTTP_FLAG_SECURE);
157 return *pHRequest;
158 }
159
160 void Downloader::run() {
161 BOOL bResults = FALSE;
162 HINTERNET hSession = NULL,
163 hConnect = NULL,
164 hRequest = NULL;
165
166 SYSTEMTIME lastModified;
167 DWORD sizeOfSystemtime = sizeof (SYSTEMTIME);
168
169 memset(&lastModified, 0, sizeof (SYSTEMTIME));
170
171 if (!openSession(&hSession)) {
172 DEBUG << "Failed to open session: " << getLastErrorMsg();
173 return;
174 }
175
176 if (!initializeConnection(hSession, &hConnect, L"www.intevation.de")) {
177 DEBUG << "Failed to initialize connection: " << getLastErrorMsg();
178 goto cleanup;
179 }
180
181 if (!createRequest(hSession, hConnect, &hRequest, L"GET", L"/")) {
182 DEBUG << "Failed to create the request: " << getLastErrorMsg();
183 goto cleanup;
184 }
185
186 if (hRequest) {
187 DEBUG << "Doing Request";
188 bResults = WinHttpSendRequest(hRequest,
189 WINHTTP_NO_ADDITIONAL_HEADERS,
190 0, WINHTTP_NO_REQUEST_DATA, 0,
191 0, 0);
192 } else {
193 DEBUG << "Error: " << GetLastError();
194 }
195
196
197 if (bResults) {
198 DEBUG << "Recieving Response";
199 bResults = WinHttpReceiveResponse(hRequest, NULL);
200 } else {
201 DEBUG << "Error: " << GetLastError();
202 }
203
204 if (bResults) {
205 DEBUG << "Querying Headers";
206 bResults = WinHttpQueryHeaders(hRequest,
207 WINHTTP_QUERY_LAST_MODIFIED |
208 WINHTTP_QUERY_FLAG_SYSTEMTIME,
209 NULL,
210 &lastModified,
211 &sizeOfSystemtime,
212 WINHTTP_NO_HEADER_INDEX);
213 } else {
214 DWORD errCode = GetLastError();
215 switch (errCode) {
216 case ERROR_WINHTTP_HEADER_NOT_FOUND:
217 DEBUG << "Header not found";
218 break;
219 case ERROR_WINHTTP_INCORRECT_HANDLE_STATE:
220 DEBUG << "Incorrect handle state";
221 break;
222 case ERROR_WINHTTP_INCORRECT_HANDLE_TYPE:
223 DEBUG << "Incorrect handle type";
224 break;
225 case ERROR_WINHTTP_INTERNAL_ERROR:
226 DEBUG << "Internal error";
227 break;
228 case ERROR_NOT_ENOUGH_MEMORY:
229 DEBUG << "OOM";
230 break;
231 default:
232 DEBUG << "Error: " << getLastErrorMsg();
233 }
234 }
235
236 DEBUG << "Last modified year: " << lastModified.wYear;
237
238
239 if (!bResults) {
240 // Report any errors.
241 DEBUG << "Error" << GetLastError();
242 emit error(tr("Unknown Problem when connecting"), Unknown);
243 }
244 cleanup:
245 if (hRequest) {
246 WinHttpCloseHandle(hRequest);
247 }
248
249 if (hConnect) {
250 WinHttpCloseHandle(hConnect);
251
252 }
253
254 if (hSession) {
255 WinHttpCloseHandle(hSession);
256 }
257 return;
258 }
259 #endif

http://wald.intevation.org/projects/trustbridge/