LibreOffice Module shell (master) 1
wininetbackend.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <cstddef>
23#include <string_view>
24
26#include <com/sun/star/uno/XComponentContext.hpp>
27#include <o3tl/string_view.hxx>
28#include <rtl/ustrbuf.hxx>
29#include <sal/log.hxx>
30
31#include "wininetbackend.hxx"
32
33#if !defined WIN32_LEAN_AND_MEAN
34# define WIN32_LEAN_AND_MEAN
35#endif
36#include <windows.h>
37#include <wininet.h>
38#include <sal/alloca.h>
39
40#define WININET_DLL_NAME L"wininet.dll"
41#define EQUAL_SIGN '='
42#define COLON ':'
43#define SPACE ' '
44#define SEMI_COLON ';'
45
46namespace {
47
48struct Library {
49 HMODULE module;
50
51 explicit Library(HMODULE theModule): module(theModule) {}
52
53 ~Library() { if (module) FreeLibrary(module); }
54};
55
56struct ProxyEntry
57{
58 OUString Server;
59 OUString Port;
60};
61
62 ProxyEntry ReadProxyEntry(std::u16string_view aProxy, std::size_t& i)
63 {
64 ProxyEntry aProxyEntry;
65
66 aProxyEntry.Server = o3tl::getToken( aProxy, COLON, i );
67 if ( i != std::u16string_view::npos )
68 aProxyEntry.Port = o3tl::getToken( aProxy, COLON, i );
69
70 return aProxyEntry;
71 }
72
73 ProxyEntry FindProxyEntry(std::u16string_view aProxyList, std::u16string_view aType)
74 {
75 std::size_t nIndex = 0;
76
77 do
78 {
79 // get the next token, e.g. ftp=server:port
80 std::u16string_view nextToken = o3tl::getToken( aProxyList, SPACE, nIndex );
81
82 // split the next token again into the parts separated
83 // through '=', e.g. ftp=server:port -> ftp and server:port
84 std::size_t i = 0;
85 if( nextToken.find( EQUAL_SIGN ) != std::u16string_view::npos )
86 {
87 if( aType == o3tl::getToken( nextToken, EQUAL_SIGN, i ) )
88 return ReadProxyEntry(nextToken, i);
89 }
90 else if( aType.empty())
91 return ReadProxyEntry(nextToken, i);
92
93 } while ( nIndex != std::u16string_view::npos );
94
95 return ProxyEntry();
96 }
97
98} // unnamed namespace
99
101{
102 Library hWinInetDll( LoadLibraryW( WININET_DLL_NAME ) );
103 if( hWinInetDll.module )
104 {
105 typedef BOOL ( WINAPI *InternetQueryOption_Proc_T )( HINTERNET, DWORD, LPVOID, LPDWORD );
106
107 InternetQueryOption_Proc_T lpfnInternetQueryOption =
108 reinterpret_cast< InternetQueryOption_Proc_T >(
109 GetProcAddress( hWinInetDll.module, "InternetQueryOptionW" ) );
110 if (lpfnInternetQueryOption)
111 {
112 // Some Windows versions would fail the InternetQueryOption call
113 // with ERROR_OUTOFMEMORY when the initial dwLength were zero (and
114 // are apparently fine with the initial sizeof (INTERNET_PROXY_INFO)
115 // and need no reallocation), while other versions fail with
116 // ERROR_INSUFFICIENT_BUFFER upon that initial dwLength and need a
117 // reallocation:
118 INTERNET_PROXY_INFO pi;
119 LPINTERNET_PROXY_INFO lpi = &pi;
120 DWORD dwLength = sizeof (pi);
121 bool ok = lpfnInternetQueryOption(
122 nullptr,
123 INTERNET_OPTION_PROXY,
124 lpi,
125 &dwLength );
126 if (!ok)
127 {
128 DWORD err = GetLastError();
129 if (err == ERROR_INSUFFICIENT_BUFFER)
130 {
131 // allocate sufficient space on the stack
132 // insufficient space on the stack results
133 // in a stack overflow exception, we assume
134 // this never happens, because of the relatively
135 // small amount of memory we need
136 // alloca is nice because it is fast and we don't
137 // have to free the allocated memory, it will be
138 // automatically done
139 lpi = static_cast< LPINTERNET_PROXY_INFO >(
140 alloca( dwLength ) );
141 ok = lpfnInternetQueryOption(
142 nullptr,
143 INTERNET_OPTION_PROXY,
144 lpi,
145 &dwLength );
146 if (!ok)
147 {
148 err = GetLastError();
149 }
150 }
151 if (!ok)
152 {
153 SAL_WARN(
154 "shell",
155 "InternetQueryOption INTERNET_OPTION_PROXY"
156 " GetLastError=" << err);
157 return;
158 }
159 }
160
161 // if a proxy is disabled, InternetQueryOption returns
162 // an empty proxy list, so we don't have to check if
163 // proxy is enabled or not
164
165 // We use InternetQueryOptionW (see https://msdn.microsoft.com/en-us/library/aa385101);
166 // it fills INTERNET_PROXY_INFO struct which is defined in WinInet.h to have LPCTSTR
167 // (i.e., the UNICODE-dependent generic string type expanding to const wchar_t* when
168 // UNICODE is defined, and InternetQueryOption macro expands to InternetQueryOptionW).
169 // Thus, it's natural to expect that W version would return wide strings. But it's not
170 // true. The W version still returns const char* in INTERNET_PROXY_INFO.
171 OUString aProxyList = OUString::createFromAscii( lpi->lpszProxy );
172 OUString aProxyBypassList = OUString::createFromAscii( lpi->lpszProxyBypass );
173
174 // override default for ProxyType, which is "0" meaning "No proxies".
175 valueProxyType_.IsPresent = true;
176 valueProxyType_.Value <<= sal_Int32(1);
177
178 // fill proxy bypass list
179 if( aProxyBypassList.getLength() > 0 )
180 {
181 OUStringBuffer aReverseList;
182 sal_Int32 nIndex = 0;
183 do
184 {
185 OUString aToken = aProxyBypassList.getToken( 0, SPACE, nIndex );
186 if ( aProxyList.indexOf( aToken ) == -1 )
187 {
188 if ( aReverseList.getLength() )
189 {
190 aReverseList.insert( 0, sal_Unicode( SEMI_COLON ) );
191 aReverseList.insert( 0, aToken );
192 }
193 else
194 aReverseList = aToken;
195 }
196 }
197 while ( nIndex >= 0 );
198
199 aProxyBypassList = aReverseList.makeStringAndClear();
200
201 valueNoProxy_.IsPresent = true;
202 valueNoProxy_.Value <<= aProxyBypassList.replace( SPACE, SEMI_COLON );
203 }
204
205 if( aProxyList.getLength() > 0 )
206 {
207
208 // this implementation follows the algorithm
209 // of the internet explorer
210 // if there are type-dependent proxy settings
211 // and type independent proxy settings in the
212 // registry the internet explorer chooses the
213 // type independent proxy for all settings
214 // e.g. imagine the following registry entry
215 // ftp=server:port;http=server:port;server:port
216 // the last token server:port is type independent
217 // so the ie chooses this proxy server
218
219 // if there is no port specified for a type independent
220 // server the ie uses the port of an http server if
221 // there is one and it has a port
222
223
224 ProxyEntry aTypeIndepProxy = FindProxyEntry( aProxyList, u"");
225 ProxyEntry aHttpProxy = FindProxyEntry( aProxyList, u"http" );
226 ProxyEntry aHttpsProxy = FindProxyEntry( aProxyList, u"https" );
227
228 ProxyEntry aFtpProxy = FindProxyEntry( aProxyList, u"ftp" );
229
230 if( aTypeIndepProxy.Server.getLength() )
231 {
232 aHttpProxy.Server = aTypeIndepProxy.Server;
233 aHttpsProxy.Server = aTypeIndepProxy.Server;
234 aFtpProxy.Server = aTypeIndepProxy.Server;
235
236 if( aTypeIndepProxy.Port.getLength() )
237 {
238 aHttpProxy.Port = aTypeIndepProxy.Port;
239 aHttpsProxy.Port = aTypeIndepProxy.Port;
240 aFtpProxy.Port = aTypeIndepProxy.Port;
241 }
242 else
243 {
244 aFtpProxy.Port = aHttpProxy.Port;
245 aHttpsProxy.Port = aHttpProxy.Port;
246 }
247 }
248
249 // http proxy name
250 if( aHttpProxy.Server.getLength() > 0 )
251 {
252 valueHttpProxyName_.IsPresent = true;
253 valueHttpProxyName_.Value <<= aHttpProxy.Server;
254 }
255
256 // http proxy port
257 if( aHttpProxy.Port.getLength() > 0 )
258 {
259 valueHttpProxyPort_.IsPresent = true;
260 valueHttpProxyPort_.Value <<= aHttpProxy.Port.toInt32();
261 }
262
263 // https proxy name
264 if( aHttpsProxy.Server.getLength() > 0 )
265 {
266 valueHttpsProxyName_.IsPresent = true;
267 valueHttpsProxyName_.Value <<= aHttpsProxy.Server;
268 }
269
270 // https proxy port
271 if( aHttpsProxy.Port.getLength() > 0 )
272 {
273 valueHttpsProxyPort_.IsPresent = true;
274 valueHttpsProxyPort_.Value <<= aHttpsProxy.Port.toInt32();
275 }
276
277 // ftp proxy name
278 if( aFtpProxy.Server.getLength() > 0 )
279 {
280 valueFtpProxyName_.IsPresent = true;
281 valueFtpProxyName_.Value <<= aFtpProxy.Server;
282 }
283
284 // ftp proxy port
285 if( aFtpProxy.Port.getLength() > 0 )
286 {
287 valueFtpProxyPort_.IsPresent = true;
288 valueFtpProxyPort_.Value <<= aFtpProxy.Port.toInt32();
289 }
290 }
291 }
292 }
293}
294
296{
297}
298
300 OUString const &, css::uno::Any const &)
301{
302 throw css::lang::IllegalArgumentException(
303 "setPropertyValue not supported",
304 getXWeak(), -1);
305}
306
308 OUString const & PropertyName)
309{
310 if ( PropertyName == "ooInetFTPProxyName" )
311 {
312 return css::uno::Any(valueFtpProxyName_);
313 } else if ( PropertyName == "ooInetFTPProxyPort" )
314 {
315 return css::uno::Any(valueFtpProxyPort_);
316 } else if ( PropertyName == "ooInetHTTPProxyName" )
317 {
318 return css::uno::Any(valueHttpProxyName_);
319 } else if ( PropertyName == "ooInetHTTPProxyPort" )
320 {
321 return css::uno::Any(valueHttpProxyPort_);
322 } else if ( PropertyName == "ooInetHTTPSProxyName" )
323 {
324 return css::uno::Any(valueHttpsProxyName_);
325 } else if ( PropertyName == "ooInetHTTPSProxyPort" )
326 {
327 return css::uno::Any(valueHttpsProxyPort_);
328 } else if ( PropertyName == "ooInetNoProxy" )
329 {
330 return css::uno::Any(valueNoProxy_);
331 } else if ( PropertyName == "ooInetProxyType" )
332 {
333 return css::uno::Any(valueProxyType_);
334 } else {
335 throw css::beans::UnknownPropertyException(
336 PropertyName, getXWeak());
337 }
338}
339
341{
342 return "com.sun.star.comp.configuration.backend.WinInetBackend" ;
343}
344
345sal_Bool SAL_CALL WinInetBackend::supportsService(const OUString& aServiceName)
346{
347 return cppu::supportsService(this, aServiceName);
348}
349
350uno::Sequence<OUString> SAL_CALL WinInetBackend::getSupportedServiceNames()
351{
352 return { "com.sun.star.configuration.backend.WinInetBackend" };
353}
354
355extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
357 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
358{
359 return cppu::acquire(new WinInetBackend);
360}
361
362
363/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
~WinInetBackend() override
Destructor.
css::beans::Optional< css::uno::Any > valueFtpProxyPort_
css::beans::Optional< css::uno::Any > valueHttpsProxyPort_
WinInetBackend()
Service constructor from a service factory.
virtual void SAL_CALL setPropertyValue(OUString const &, css::uno::Any const &) override
virtual css::uno::Any SAL_CALL getPropertyValue(OUString const &PropertyName) override
virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
css::beans::Optional< css::uno::Any > valueFtpProxyName_
css::beans::Optional< css::uno::Any > valueNoProxy_
virtual sal_Bool SAL_CALL supportsService(const OUString &aServiceName) override
virtual OUString SAL_CALL getImplementationName() override
css::beans::Optional< css::uno::Any > valueHttpProxyPort_
css::beans::Optional< css::uno::Any > valueHttpProxyName_
css::beans::Optional< css::uno::Any > valueHttpsProxyName_
css::beans::Optional< css::uno::Any > valueProxyType_
float u
sal_Int32 nIndex
#define SAL_WARN(area, stream)
#define SPACE
Definition: macbackend.mm:39
err
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
module
const wchar_t *typedef BOOL
unsigned char sal_Bool
sal_uInt16 sal_Unicode
#define SEMI_COLON
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * shell_WinInetBackend_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
#define SPACE
#define WININET_DLL_NAME
#define COLON
#define EQUAL_SIGN