]>
Commit | Line | Data |
---|---|---|
23c9e63c DD |
1 | /* |
2 | * Copyright (c) 2000, Red Hat, Inc. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by DJ Delorie <dj@cygnus.com> | |
13 | * | |
14 | */ | |
15 | ||
16 | /* The purpose of this file is to manage internet downloads using the | |
17 | Internet Explorer version 5 DLLs. To use this method, the user | |
18 | must already have installed and configured IE5. This module is | |
19 | called from netio.cc, which is called from geturl.cc */ | |
20 | ||
21 | #include "win32.h" | |
22 | ||
23 | #include "resource.h" | |
24 | #include "state.h" | |
25 | #include "dialog.h" | |
26 | #include "msg.h" | |
27 | #include "netio.h" | |
28 | #include "nio-ie5.h" | |
a10fdeb9 | 29 | #include "LogSingleton.h" |
c975851a JT |
30 | #include "setup_version.h" |
31 | #include "getopt++/StringOption.h" | |
a70f0d56 | 32 | #include <sstream> |
c975851a | 33 | |
f378fb54 JT |
34 | #ifndef IMAGE_FILE_MACHINE_ARM64 |
35 | #define IMAGE_FILE_MACHINE_ARM64 0xAA64 | |
36 | #endif | |
37 | ||
c975851a | 38 | static StringOption UserAgent ("", '\0', "user-agent", "User agent string for HTTP requests"); |
23c9e63c | 39 | |
50147e20 JT |
40 | const std::string & |
41 | determine_default_useragent(void) | |
42 | { | |
43 | static std::string default_useragent; | |
44 | ||
45 | if (!default_useragent.empty()) | |
46 | return default_useragent; | |
47 | ||
a70f0d56 JT |
48 | std::stringstream os; |
49 | os << "Windows NT " << OSMajorVersion() << "." << OSMinorVersion() << "." << OSBuildNumber(); | |
50 | ||
51 | std::string bitness = "Unknown"; | |
50147e20 | 52 | #ifdef __x86_64__ |
a70f0d56 | 53 | bitness = "Win64"; |
50147e20 | 54 | #else |
f378fb54 JT |
55 | typedef BOOL (WINAPI *PFNISWOW64PROCESS2)(HANDLE, USHORT *, USHORT *); |
56 | PFNISWOW64PROCESS2 pfnIsWow64Process2 = (PFNISWOW64PROCESS2)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process2"); | |
57 | ||
50147e20 JT |
58 | typedef BOOL (WINAPI *PFNISWOW64PROCESS)(HANDLE, PBOOL); |
59 | PFNISWOW64PROCESS pfnIsWow64Process = (PFNISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process"); | |
f378fb54 JT |
60 | |
61 | std::stringstream native_desc; | |
62 | ||
63 | USHORT processMachine, nativeMachine; | |
64 | if ((pfnIsWow64Process2) && | |
65 | (pfnIsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine))) { | |
66 | switch (nativeMachine) | |
67 | { | |
d86d832b JT |
68 | case IMAGE_FILE_MACHINE_I386: |
69 | bitness = "Win32"; | |
70 | break; | |
f378fb54 JT |
71 | case IMAGE_FILE_MACHINE_AMD64: |
72 | bitness = "WoW64"; | |
73 | break; | |
74 | case IMAGE_FILE_MACHINE_ARM64: | |
75 | bitness = "WoW64-ARM64"; | |
76 | break; | |
77 | default: | |
78 | native_desc << "WoW64-" << std::hex << nativeMachine; | |
79 | bitness = native_desc.str(); | |
80 | } | |
81 | } else if (pfnIsWow64Process) { | |
50147e20 JT |
82 | BOOL bIsWow64 = FALSE; |
83 | if (pfnIsWow64Process(GetCurrentProcess(), &bIsWow64)) | |
a70f0d56 | 84 | bitness = bIsWow64 ? "WoW64" : "Win32"; |
50147e20 JT |
85 | } |
86 | #endif | |
a70f0d56 | 87 | default_useragent = std::string("Cygwin-Setup/") + setup_version + " (" + os.str() + ";" + bitness + ")"; |
50147e20 JT |
88 | return default_useragent; |
89 | } | |
90 | ||
150fc845 SG |
91 | |
92 | class Proxy | |
93 | { | |
94 | int method; | |
95 | std::string host; | |
96 | int port; | |
97 | std::string hostport; // host:port | |
98 | ||
99 | public: | |
100 | Proxy (int method, char const *host, int port) | |
101 | : method(method), | |
102 | host(host ? host : ""), | |
103 | port(port), | |
104 | hostport(std::string(host ? host : "") + ":" + std::to_string(port)) | |
105 | {}; | |
106 | ||
107 | bool operator!= (const Proxy &o) const; | |
108 | ||
109 | DWORD type (void) const; | |
110 | char const *string (void) const; | |
111 | }; | |
112 | ||
113 | bool Proxy::operator!= (const Proxy &o) const | |
114 | { | |
115 | if (method != o.method) return true; | |
116 | if (method != IDC_NET_PROXY) return false; | |
117 | // it's only meaningful to compare host:port for method == IDC_NET_PROXY | |
118 | if (host != o.host) return true; | |
119 | if (port != o.port) return true; | |
120 | return false; | |
121 | } | |
122 | ||
123 | char const *Proxy::string(void) const | |
124 | { | |
125 | if (method == IDC_NET_PROXY) | |
126 | return hostport.c_str(); | |
127 | else | |
128 | return NULL; | |
129 | } | |
130 | ||
131 | DWORD Proxy::type (void) const | |
132 | { | |
133 | switch (method) | |
134 | { | |
135 | case IDC_NET_PROXY: return INTERNET_OPEN_TYPE_PROXY; | |
136 | case IDC_NET_PRECONFIG: return INTERNET_OPEN_TYPE_PRECONFIG; | |
137 | default: | |
138 | case IDC_NET_DIRECT: return INTERNET_OPEN_TYPE_DIRECT; | |
139 | } | |
140 | } | |
141 | ||
f75381c6 SG |
142 | static HINTERNET internet = 0; |
143 | static Proxy last_proxy = Proxy(-1, "", -1); | |
144 | ||
ccbb34d3 | 145 | NetIO_IE5::NetIO_IE5 (char const *url, bool cachable) |
23c9e63c | 146 | { |
348860fa DD |
147 | int resend = 0; |
148 | ||
f75381c6 SG |
149 | Proxy proxy = Proxy(net_method, net_proxy_host, net_proxy_port); |
150 | if (proxy != last_proxy) | |
4a83b7b0 | 151 | { |
f75381c6 SG |
152 | last_proxy = proxy; |
153 | ||
154 | if (internet != 0) | |
155 | InternetCloseHandle(internet); | |
156 | else | |
157 | InternetAttemptConnect (0); | |
c975851a | 158 | |
50147e20 | 159 | const char *lpszAgent = determine_default_useragent().c_str(); |
c975851a JT |
160 | if (UserAgent.isPresent()) |
161 | { | |
162 | const std::string &user_agent = UserAgent; | |
163 | if (user_agent.length()) | |
164 | { | |
165 | // override the default user agent string | |
166 | lpszAgent = user_agent.c_str(); | |
167 | Log (LOG_PLAIN) << "User-Agent: header overridden to \"" << lpszAgent << "\"" << endLog; | |
168 | } | |
169 | else | |
170 | { | |
171 | // user-agent option is present, but no string is specified means | |
172 | // don't add a user-agent header | |
173 | lpszAgent = NULL; | |
174 | Log (LOG_PLAIN) << "User-Agent: header suppressed " << lpszAgent << endLog; | |
175 | } | |
176 | } | |
177 | ||
f75381c6 | 178 | internet = InternetOpen (lpszAgent, proxy.type(), proxy.string(), NULL, 0); |
4a83b7b0 | 179 | } |
23c9e63c DD |
180 | |
181 | DWORD flags = | |
23c9e63c | 182 | INTERNET_FLAG_KEEP_CONNECTION | |
b24c88b3 | 183 | INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_PASSIVE; |
23c9e63c | 184 | |
ca875ed3 JT |
185 | if (!cachable) { |
186 | flags |= INTERNET_FLAG_NO_CACHE_WRITE; | |
9b9237fb JT |
187 | } else { |
188 | flags |= INTERNET_FLAG_RESYNCHRONIZE; | |
ca875ed3 JT |
189 | } |
190 | ||
f75381c6 | 191 | connection = InternetOpenUrl (internet, url, NULL, 0, flags, 0); |
348860fa | 192 | |
b24c88b3 | 193 | try_again: |
4e8ff53f DD |
194 | |
195 | if (net_user && net_passwd) | |
196 | { | |
348860fa | 197 | InternetSetOption (connection, INTERNET_OPTION_USERNAME, |
4e8ff53f | 198 | net_user, strlen (net_user)); |
348860fa | 199 | InternetSetOption (connection, INTERNET_OPTION_PASSWORD, |
4e8ff53f DD |
200 | net_passwd, strlen (net_passwd)); |
201 | } | |
202 | ||
23c9e63c DD |
203 | if (net_proxy_user && net_proxy_passwd) |
204 | { | |
348860fa | 205 | InternetSetOption (connection, INTERNET_OPTION_PROXY_USERNAME, |
23c9e63c | 206 | net_proxy_user, strlen (net_proxy_user)); |
348860fa | 207 | InternetSetOption (connection, INTERNET_OPTION_PROXY_PASSWORD, |
23c9e63c DD |
208 | net_proxy_passwd, strlen (net_proxy_passwd)); |
209 | } | |
210 | ||
348860fa DD |
211 | if (resend) |
212 | if (!HttpSendRequest (connection, 0, 0, 0, 0)) | |
213 | connection = 0; | |
23c9e63c DD |
214 | |
215 | if (!connection) | |
216 | { | |
a10fdeb9 JT |
217 | DWORD e = GetLastError (); |
218 | if (e == ERROR_INTERNET_EXTENDED_ERROR) | |
23c9e63c DD |
219 | { |
220 | char buf[2000]; | |
b24c88b3 | 221 | DWORD e, l = sizeof (buf); |
23c9e63c | 222 | InternetGetLastResponseInfo (&e, buf, &l); |
e0373ab5 | 223 | mbox (0, buf, "Internet Error", MB_OK); |
23c9e63c | 224 | } |
a10fdeb9 JT |
225 | else |
226 | { | |
227 | Log (LOG_PLAIN) << "connection error: " << e << endLog; | |
228 | } | |
23c9e63c | 229 | } |
4e8ff53f | 230 | |
a7b37e4e JT |
231 | ULONG type = 0; |
232 | DWORD type_s = sizeof (type); | |
4e8ff53f DD |
233 | InternetQueryOption (connection, INTERNET_OPTION_HANDLE_TYPE, |
234 | &type, &type_s); | |
235 | ||
236 | switch (type) | |
237 | { | |
238 | case INTERNET_HANDLE_TYPE_HTTP_REQUEST: | |
239 | case INTERNET_HANDLE_TYPE_CONNECT_HTTP: | |
240 | type_s = sizeof (DWORD); | |
241 | if (HttpQueryInfo (connection, | |
242 | HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, | |
243 | &type, &type_s, NULL)) | |
244 | { | |
a10fdeb9 JT |
245 | if (type != 200) |
246 | Log (LOG_PLAIN) << "HTTP status " << type << " fetching " << url << endLog; | |
247 | ||
b24c88b3 | 248 | if (type == 401) /* authorization required */ |
4e8ff53f | 249 | { |
b24c88b3 | 250 | flush_io (); |
ab57ceaa | 251 | get_auth (NULL); |
348860fa | 252 | resend = 1; |
4e8ff53f DD |
253 | goto try_again; |
254 | } | |
b24c88b3 | 255 | else if (type == 407) /* proxy authorization required */ |
4e8ff53f | 256 | { |
b24c88b3 | 257 | flush_io (); |
ab57ceaa | 258 | get_proxy_auth (NULL); |
348860fa | 259 | resend = 1; |
4e8ff53f DD |
260 | goto try_again; |
261 | } | |
262 | else if (type >= 300) | |
263 | { | |
ca875ed3 | 264 | InternetCloseHandle (connection); |
4e8ff53f DD |
265 | connection = 0; |
266 | return; | |
267 | } | |
268 | } | |
269 | } | |
a7b37e4e JT |
270 | |
271 | InternetQueryOption (connection, INTERNET_OPTION_REQUEST_FLAGS, | |
272 | &type, &type_s); | |
273 | if (type & INTERNET_REQFLAG_FROM_CACHE) | |
274 | Log (LOG_BABBLE) << "Request for URL " << url << " satisfied from cache" << endLog; | |
23c9e63c DD |
275 | } |
276 | ||
348860fa DD |
277 | void |
278 | NetIO_IE5::flush_io () | |
279 | { | |
280 | DWORD actual = 0; | |
281 | char buf[1024]; | |
b24c88b3 RC |
282 | do |
283 | { | |
284 | InternetReadFile (connection, buf, 1024, &actual); | |
285 | } | |
286 | while (actual > 0); | |
348860fa DD |
287 | } |
288 | ||
23c9e63c DD |
289 | NetIO_IE5::~NetIO_IE5 () |
290 | { | |
291 | if (connection) | |
292 | InternetCloseHandle (connection); | |
293 | } | |
294 | ||
295 | int | |
296 | NetIO_IE5::ok () | |
297 | { | |
298 | return (connection == NULL) ? 0 : 1; | |
299 | } | |
300 | ||
301 | int | |
302 | NetIO_IE5::read (char *buf, int nbytes) | |
303 | { | |
ca875ed3 JT |
304 | #define READ_CHUNK (64 * 1024) |
305 | /* Read in chunks rather than the whole file at once, so we can do progress | |
306 | reporting */ | |
307 | if (nbytes > READ_CHUNK) | |
308 | nbytes = READ_CHUNK; | |
309 | ||
23c9e63c DD |
310 | DWORD actual; |
311 | if (InternetReadFile (connection, buf, nbytes, &actual)) | |
312 | return actual; | |
ca875ed3 | 313 | |
23c9e63c DD |
314 | return -1; |
315 | } |