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
);
38 determine_default_useragent(void)
40 static std::string default_useragent
;
42 if (!default_useragent
.empty())
43 return default_useragent
;
46 os
<< "Windows NT " << OSMajorVersion() << "." << OSMinorVersion() << "." << OSBuildNumber();
49 USHORT processMachine
= IMAGE_FILE_MACHINE_AMD64
;
51 USHORT processMachine
= IMAGE_FILE_MACHINE_I386
;
54 USHORT nativeMachine
= WowNativeMachine();
57 if (processMachine
!= nativeMachine
)
58 bitness
= machine_name(processMachine
) + "-on-" + machine_name(nativeMachine
);
60 bitness
= machine_name(processMachine
);
62 typedef LANGID (WINAPI
*PFNGETTHREADUILANGUAGE
)();
63 PFNGETTHREADUILANGUAGE pfnGetThreadUILanguage
= (PFNGETTHREADUILANGUAGE
)GetProcAddress(GetModuleHandle("kernel32"), "GetThreadUILanguage");
64 std::stringstream langid
;
65 if (pfnGetThreadUILanguage
)
67 LANGID l
= pfnGetThreadUILanguage();
68 langid
<< std::hex
<< std::setw(4) << std::setfill('0') << l
;
71 std::string symlinks
= "";
72 if (nt_sec
.hasSymlinkCreationRights())
73 symlinks
.append("SymLinkPriv");
74 if (is_developer_mode())
76 if (!symlinks
.empty())
78 symlinks
.append("UnprivilegedSymLink");
81 default_useragent
= std::string("Cygwin-Setup/") + setup_version
+ " (" + os
.str() + ";" + bitness
+ ";" + langid
.str() + ";" + symlinks
+ ")";
82 Log (LOG_BABBLE
) << "User-Agent: default is \"" << default_useragent
<< "\"" << endLog
;
84 return default_useragent
;
93 std::string hostport
; // host:port
96 Proxy (int method
, char const *host
, int port
)
98 host(host
? host
: ""),
100 hostport(std::string(host
? host
: "") + ":" + std::to_string(port
))
103 bool operator!= (const Proxy
&o
) const;
105 DWORD
type (void) const;
106 char const *string (void) const;
109 bool Proxy::operator!= (const Proxy
&o
) const
111 if (method
!= o
.method
) return true;
112 if (method
!= IDC_NET_PROXY
) return false;
113 // it's only meaningful to compare host:port for method == IDC_NET_PROXY
114 if (host
!= o
.host
) return true;
115 if (port
!= o
.port
) return true;
119 char const *Proxy::string(void) const
121 if (method
== IDC_NET_PROXY
)
122 return hostport
.c_str();
127 DWORD
Proxy::type (void) const
131 case IDC_NET_PROXY
: return INTERNET_OPEN_TYPE_PROXY
;
132 case IDC_NET_PRECONFIG
: return INTERNET_OPEN_TYPE_PRECONFIG
;
134 case IDC_NET_DIRECT
: return INTERNET_OPEN_TYPE_DIRECT
;
138 static HINTERNET internet
= 0;
139 static Proxy last_proxy
= Proxy(-1, "", -1);
141 NetIO_IE5::NetIO_IE5 (char const *url
, bool cachable
)
145 Proxy proxy
= Proxy(net_method
, net_proxy_host
, net_proxy_port
);
146 if (proxy
!= last_proxy
)
151 InternetCloseHandle(internet
);
153 InternetAttemptConnect (0);
155 const char *lpszAgent
= determine_default_useragent().c_str();
156 if (UserAgent
.isPresent())
158 const std::string
&user_agent
= UserAgent
;
159 if (user_agent
.length())
161 // override the default user agent string
162 lpszAgent
= user_agent
.c_str();
163 Log (LOG_PLAIN
) << "User-Agent: header overridden to \"" << lpszAgent
<< "\"" << endLog
;
167 // user-agent option is present, but no string is specified means
168 // don't add a user-agent header
170 Log (LOG_PLAIN
) << "User-Agent: header suppressed " << lpszAgent
<< endLog
;
174 internet
= InternetOpen (lpszAgent
, proxy
.type(), proxy
.string(), NULL
, 0);
178 INTERNET_FLAG_KEEP_CONNECTION
|
179 INTERNET_FLAG_EXISTING_CONNECT
| INTERNET_FLAG_PASSIVE
;
182 flags
|= INTERNET_FLAG_NO_CACHE_WRITE
;
184 flags
|= INTERNET_FLAG_RESYNCHRONIZE
;
187 connection
= InternetOpenUrl (internet
, url
, NULL
, 0, flags
, 0);
191 if (net_user
&& net_passwd
)
193 InternetSetOption (connection
, INTERNET_OPTION_USERNAME
,
194 net_user
, strlen (net_user
));
195 InternetSetOption (connection
, INTERNET_OPTION_PASSWORD
,
196 net_passwd
, strlen (net_passwd
));
199 if (net_proxy_user
&& net_proxy_passwd
)
201 InternetSetOption (connection
, INTERNET_OPTION_PROXY_USERNAME
,
202 net_proxy_user
, strlen (net_proxy_user
));
203 InternetSetOption (connection
, INTERNET_OPTION_PROXY_PASSWORD
,
204 net_proxy_passwd
, strlen (net_proxy_passwd
));
208 if (!HttpSendRequest (connection
, 0, 0, 0, 0))
213 DWORD e
= GetLastError ();
214 if (e
== ERROR_INTERNET_EXTENDED_ERROR
)
217 DWORD e
, l
= sizeof (buf
);
218 InternetGetLastResponseInfo (&e
, buf
, &l
);
220 // show errors apart from file-not-found (e doesn't contain the
221 // response code so we have to resort to looking at the message)
222 if (strncmp("550", buf
, 3) != 0)
223 mbox (0, IDS_NIO_ERROR
, MB_OK
, buf
);
225 for (unsigned int i
= 0; i
< l
; i
++)
226 if (buf
[i
] == '\n' or buf
[i
] == '\r')
228 Log (LOG_PLAIN
) << "connection error: " << buf
<< " fetching " << url
<< endLog
;
232 Log (LOG_PLAIN
) << "connection error: " << e
<< " fetching " << url
<< endLog
;
237 DWORD type_s
= sizeof (type
);
238 InternetQueryOption (connection
, INTERNET_OPTION_HANDLE_TYPE
,
243 case INTERNET_HANDLE_TYPE_HTTP_REQUEST
:
244 case INTERNET_HANDLE_TYPE_CONNECT_HTTP
:
245 type_s
= sizeof (DWORD
);
246 if (HttpQueryInfo (connection
,
247 HTTP_QUERY_STATUS_CODE
| HTTP_QUERY_FLAG_NUMBER
,
248 &type
, &type_s
, NULL
))
251 Log (LOG_PLAIN
) << "HTTP status " << type
<< " fetching " << url
<< endLog
;
253 if (type
== 401) /* authorization required */
260 else if (type
== 407) /* proxy authorization required */
263 get_proxy_auth (NULL
);
267 else if (type
>= 300)
269 InternetCloseHandle (connection
);
276 InternetQueryOption (connection
, INTERNET_OPTION_REQUEST_FLAGS
,
278 if (type
& INTERNET_REQFLAG_FROM_CACHE
)
279 Log (LOG_BABBLE
) << "Request for URL " << url
<< " satisfied from cache" << endLog
;
283 NetIO_IE5::flush_io ()
289 InternetReadFile (connection
, buf
, 1024, &actual
);
294 NetIO_IE5::~NetIO_IE5 ()
297 InternetCloseHandle (connection
);
303 return (connection
== NULL
) ? 0 : 1;
307 NetIO_IE5::read (char *buf
, int nbytes
)
309 #define READ_CHUNK (64 * 1024)
310 /* Read in chunks rather than the whole file at once, so we can do progress
312 if (nbytes
> READ_CHUNK
)
316 if (InternetReadFile (connection
, buf
, nbytes
, &actual
))