2 * Copyright (c) 2000, Red Hat, Inc.
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.
9 * A copy of the GNU General Public License can be found at
12 * Written by DJ Delorie <dj@cygnus.com>
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 */
29 #include "LogSingleton.h"
30 #include "setup_version.h"
31 #include "getopt++/StringOption.h"
35 static StringOption
UserAgent ("", '\0', "user-agent", IDS_HELPTEXT_USER_AGENT
);
37 static const std::string
38 machine_name(USHORT machine
)
42 case IMAGE_FILE_MACHINE_I386
:
45 case IMAGE_FILE_MACHINE_AMD64
:
48 case IMAGE_FILE_MACHINE_ARM64
:
52 std::stringstream machine_desc
;
53 machine_desc
<< std::hex
<< machine
;
54 return machine_desc
.str();
59 determine_default_useragent(void)
61 static std::string default_useragent
;
63 if (!default_useragent
.empty())
64 return default_useragent
;
67 os
<< "Windows NT " << OSMajorVersion() << "." << OSMinorVersion() << "." << OSBuildNumber();
70 USHORT processMachine
= IMAGE_FILE_MACHINE_AMD64
;
72 USHORT processMachine
= IMAGE_FILE_MACHINE_I386
;
75 USHORT nativeMachine
= WowNativeMachine();
78 if (processMachine
!= nativeMachine
)
79 bitness
= machine_name(processMachine
) + "-on-" + machine_name(nativeMachine
);
81 bitness
= machine_name(processMachine
);
83 typedef LANGID (WINAPI
*PFNGETTHREADUILANGUAGE
)();
84 PFNGETTHREADUILANGUAGE pfnGetThreadUILanguage
= (PFNGETTHREADUILANGUAGE
)GetProcAddress(GetModuleHandle("kernel32"), "GetThreadUILanguage");
85 std::stringstream langid
;
86 if (pfnGetThreadUILanguage
)
88 LANGID l
= pfnGetThreadUILanguage();
89 langid
<< std::hex
<< std::setw(4) << std::setfill('0') << l
;
92 std::string symlinks
= "";
93 if (nt_sec
.hasSymlinkCreationRights())
94 symlinks
.append("SymLinkPriv");
95 if (is_developer_mode())
97 if (!symlinks
.empty())
99 symlinks
.append("UnprivilegedSymLink");
102 default_useragent
= std::string("Cygwin-Setup/") + setup_version
+ " (" + os
.str() + ";" + bitness
+ ";" + langid
.str() + ";" + symlinks
+ ")";
103 Log (LOG_BABBLE
) << "User-Agent: default is \"" << default_useragent
<< "\"" << endLog
;
105 return default_useragent
;
114 std::string hostport
; // host:port
117 Proxy (int method
, char const *host
, int port
)
119 host(host
? host
: ""),
121 hostport(std::string(host
? host
: "") + ":" + std::to_string(port
))
124 bool operator!= (const Proxy
&o
) const;
126 DWORD
type (void) const;
127 char const *string (void) const;
130 bool Proxy::operator!= (const Proxy
&o
) const
132 if (method
!= o
.method
) return true;
133 if (method
!= IDC_NET_PROXY
) return false;
134 // it's only meaningful to compare host:port for method == IDC_NET_PROXY
135 if (host
!= o
.host
) return true;
136 if (port
!= o
.port
) return true;
140 char const *Proxy::string(void) const
142 if (method
== IDC_NET_PROXY
)
143 return hostport
.c_str();
148 DWORD
Proxy::type (void) const
152 case IDC_NET_PROXY
: return INTERNET_OPEN_TYPE_PROXY
;
153 case IDC_NET_PRECONFIG
: return INTERNET_OPEN_TYPE_PRECONFIG
;
155 case IDC_NET_DIRECT
: return INTERNET_OPEN_TYPE_DIRECT
;
159 static HINTERNET internet
= 0;
160 static Proxy last_proxy
= Proxy(-1, "", -1);
162 NetIO_IE5::NetIO_IE5 (char const *url
, bool cachable
)
166 Proxy proxy
= Proxy(net_method
, net_proxy_host
, net_proxy_port
);
167 if (proxy
!= last_proxy
)
172 InternetCloseHandle(internet
);
174 InternetAttemptConnect (0);
176 const char *lpszAgent
= determine_default_useragent().c_str();
177 if (UserAgent
.isPresent())
179 const std::string
&user_agent
= UserAgent
;
180 if (user_agent
.length())
182 // override the default user agent string
183 lpszAgent
= user_agent
.c_str();
184 Log (LOG_PLAIN
) << "User-Agent: header overridden to \"" << lpszAgent
<< "\"" << endLog
;
188 // user-agent option is present, but no string is specified means
189 // don't add a user-agent header
191 Log (LOG_PLAIN
) << "User-Agent: header suppressed " << lpszAgent
<< endLog
;
195 internet
= InternetOpen (lpszAgent
, proxy
.type(), proxy
.string(), NULL
, 0);
199 INTERNET_FLAG_KEEP_CONNECTION
|
200 INTERNET_FLAG_EXISTING_CONNECT
| INTERNET_FLAG_PASSIVE
;
203 flags
|= INTERNET_FLAG_NO_CACHE_WRITE
;
205 flags
|= INTERNET_FLAG_RESYNCHRONIZE
;
208 connection
= InternetOpenUrl (internet
, url
, NULL
, 0, flags
, 0);
212 if (net_user
&& net_passwd
)
214 InternetSetOption (connection
, INTERNET_OPTION_USERNAME
,
215 net_user
, strlen (net_user
));
216 InternetSetOption (connection
, INTERNET_OPTION_PASSWORD
,
217 net_passwd
, strlen (net_passwd
));
220 if (net_proxy_user
&& net_proxy_passwd
)
222 InternetSetOption (connection
, INTERNET_OPTION_PROXY_USERNAME
,
223 net_proxy_user
, strlen (net_proxy_user
));
224 InternetSetOption (connection
, INTERNET_OPTION_PROXY_PASSWORD
,
225 net_proxy_passwd
, strlen (net_proxy_passwd
));
229 if (!HttpSendRequest (connection
, 0, 0, 0, 0))
234 DWORD e
= GetLastError ();
235 if (e
== ERROR_INTERNET_EXTENDED_ERROR
)
238 DWORD e
, l
= sizeof (buf
);
239 InternetGetLastResponseInfo (&e
, buf
, &l
);
241 // show errors apart from file-not-found (e doesn't contain the
242 // response code so we have to resort to looking at the message)
243 if (strncmp("550", buf
, 3) != 0)
244 mbox (0, IDS_NIO_ERROR
, MB_OK
, buf
);
246 for (unsigned int i
= 0; i
< l
; i
++)
247 if (buf
[i
] == '\n' or buf
[i
] == '\r')
249 Log (LOG_PLAIN
) << "connection error: " << buf
<< " fetching " << url
<< endLog
;
253 Log (LOG_PLAIN
) << "connection error: " << e
<< " fetching " << url
<< endLog
;
258 DWORD type_s
= sizeof (type
);
259 InternetQueryOption (connection
, INTERNET_OPTION_HANDLE_TYPE
,
264 case INTERNET_HANDLE_TYPE_HTTP_REQUEST
:
265 case INTERNET_HANDLE_TYPE_CONNECT_HTTP
:
266 type_s
= sizeof (DWORD
);
267 if (HttpQueryInfo (connection
,
268 HTTP_QUERY_STATUS_CODE
| HTTP_QUERY_FLAG_NUMBER
,
269 &type
, &type_s
, NULL
))
272 Log (LOG_PLAIN
) << "HTTP status " << type
<< " fetching " << url
<< endLog
;
274 if (type
== 401) /* authorization required */
281 else if (type
== 407) /* proxy authorization required */
284 get_proxy_auth (NULL
);
288 else if (type
>= 300)
290 InternetCloseHandle (connection
);
297 InternetQueryOption (connection
, INTERNET_OPTION_REQUEST_FLAGS
,
299 if (type
& INTERNET_REQFLAG_FROM_CACHE
)
300 Log (LOG_BABBLE
) << "Request for URL " << url
<< " satisfied from cache" << endLog
;
304 NetIO_IE5::flush_io ()
310 InternetReadFile (connection
, buf
, 1024, &actual
);
315 NetIO_IE5::~NetIO_IE5 ()
318 InternetCloseHandle (connection
);
324 return (connection
== NULL
) ? 0 : 1;
328 NetIO_IE5::read (char *buf
, int nbytes
)
330 #define READ_CHUNK (64 * 1024)
331 /* Read in chunks rather than the whole file at once, so we can do progress
333 if (nbytes
> READ_CHUNK
)
337 if (InternetReadFile (connection
, buf
, nbytes
, &actual
))