1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
23 #include <string_view>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <com/sun/star/uno/XComponentContext.hpp>
27 #include <o3tl/string_view.hxx>
28 #include <rtl/ustrbuf.hxx>
29 #include <sal/log.hxx>
31 #include "wininetbackend.hxx"
33 #if !defined WIN32_LEAN_AND_MEAN
34 # define WIN32_LEAN_AND_MEAN
38 #include <sal/alloca.h>
40 #define WININET_DLL_NAME L"wininet.dll"
41 #define EQUAL_SIGN '='
44 #define SEMI_COLON ';'
51 explicit Library(HMODULE theModule
): module(theModule
) {}
53 ~Library() { if (module
) FreeLibrary(module
); }
62 ProxyEntry
ReadProxyEntry(std::u16string_view aProxy
, std::size_t& i
)
64 ProxyEntry aProxyEntry
;
66 aProxyEntry
.Server
= o3tl::getToken( aProxy
, COLON
, i
);
67 if ( i
!= std::u16string_view::npos
)
68 aProxyEntry
.Port
= o3tl::getToken( aProxy
, COLON
, i
);
73 ProxyEntry
FindProxyEntry(std::u16string_view aProxyList
, std::u16string_view aType
)
75 std::size_t nIndex
= 0;
79 // get the next token, e.g. ftp=server:port
80 std::u16string_view nextToken
= o3tl::getToken( aProxyList
, SPACE
, nIndex
);
82 // split the next token again into the parts separated
83 // through '=', e.g. ftp=server:port -> ftp and server:port
85 if( nextToken
.find( EQUAL_SIGN
) != std::u16string_view::npos
)
87 if( aType
== o3tl::getToken( nextToken
, EQUAL_SIGN
, i
) )
88 return ReadProxyEntry(nextToken
, i
);
90 else if( aType
.empty())
91 return ReadProxyEntry(nextToken
, i
);
93 } while ( nIndex
!= std::u16string_view::npos
);
98 } // unnamed namespace
100 WinInetBackend::WinInetBackend()
102 Library
hWinInetDll( LoadLibraryW( WININET_DLL_NAME
) );
103 if( hWinInetDll
.module
)
105 typedef BOOL ( WINAPI
*InternetQueryOption_Proc_T
)( HINTERNET
, DWORD
, LPVOID
, LPDWORD
);
107 InternetQueryOption_Proc_T lpfnInternetQueryOption
=
108 reinterpret_cast< InternetQueryOption_Proc_T
>(
109 GetProcAddress( hWinInetDll
.module
, "InternetQueryOptionW" ) );
110 if (lpfnInternetQueryOption
)
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
118 INTERNET_PROXY_INFO pi
;
119 LPINTERNET_PROXY_INFO lpi
= &pi
;
120 DWORD dwLength
= sizeof (pi
);
121 bool ok
= lpfnInternetQueryOption(
123 INTERNET_OPTION_PROXY
,
128 DWORD err
= GetLastError();
129 if (err
== ERROR_INSUFFICIENT_BUFFER
)
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(
143 INTERNET_OPTION_PROXY
,
148 err
= GetLastError();
155 "InternetQueryOption INTERNET_OPTION_PROXY"
156 " GetLastError=" << err
);
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
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
);
174 // override default for ProxyType, which is "0" meaning "No proxies".
175 valueProxyType_
.IsPresent
= true;
176 valueProxyType_
.Value
<<= sal_Int32(1);
178 // fill proxy bypass list
179 if( aProxyBypassList
.getLength() > 0 )
181 OUStringBuffer aReverseList
;
182 sal_Int32 nIndex
= 0;
185 OUString aToken
= aProxyBypassList
.getToken( 0, SPACE
, nIndex
);
186 if ( aProxyList
.indexOf( aToken
) == -1 )
188 if ( aReverseList
.getLength() )
190 aReverseList
.insert( 0, sal_Unicode( SEMI_COLON
) );
191 aReverseList
.insert( 0, aToken
);
194 aReverseList
= aToken
;
197 while ( nIndex
>= 0 );
199 aProxyBypassList
= aReverseList
.makeStringAndClear();
201 valueNoProxy_
.IsPresent
= true;
202 valueNoProxy_
.Value
<<= aProxyBypassList
.replace( SPACE
, SEMI_COLON
);
205 if( aProxyList
.getLength() > 0 )
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
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
224 ProxyEntry aTypeIndepProxy
= FindProxyEntry( aProxyList
, u
"");
225 ProxyEntry aHttpProxy
= FindProxyEntry( aProxyList
, u
"http" );
226 ProxyEntry aHttpsProxy
= FindProxyEntry( aProxyList
, u
"https" );
228 if( aTypeIndepProxy
.Server
.getLength() )
230 aHttpProxy
.Server
= aTypeIndepProxy
.Server
;
231 aHttpsProxy
.Server
= aTypeIndepProxy
.Server
;
233 if( aTypeIndepProxy
.Port
.getLength() )
235 aHttpProxy
.Port
= aTypeIndepProxy
.Port
;
236 aHttpsProxy
.Port
= aTypeIndepProxy
.Port
;
240 aHttpsProxy
.Port
= aHttpProxy
.Port
;
245 if( aHttpProxy
.Server
.getLength() > 0 )
247 valueHttpProxyName_
.IsPresent
= true;
248 valueHttpProxyName_
.Value
<<= aHttpProxy
.Server
;
252 if( aHttpProxy
.Port
.getLength() > 0 )
254 valueHttpProxyPort_
.IsPresent
= true;
255 valueHttpProxyPort_
.Value
<<= aHttpProxy
.Port
.toInt32();
259 if( aHttpsProxy
.Server
.getLength() > 0 )
261 valueHttpsProxyName_
.IsPresent
= true;
262 valueHttpsProxyName_
.Value
<<= aHttpsProxy
.Server
;
266 if( aHttpsProxy
.Port
.getLength() > 0 )
268 valueHttpsProxyPort_
.IsPresent
= true;
269 valueHttpsProxyPort_
.Value
<<= aHttpsProxy
.Port
.toInt32();
276 WinInetBackend::~WinInetBackend()
280 void WinInetBackend::setPropertyValue(
281 OUString
const &, css::uno::Any
const &)
283 throw css::lang::IllegalArgumentException(
284 "setPropertyValue not supported",
288 css::uno::Any
WinInetBackend::getPropertyValue(
289 OUString
const & PropertyName
)
291 if (PropertyName
== "ooInetHTTPProxyName")
293 return css::uno::Any(valueHttpProxyName_
);
294 } else if ( PropertyName
== "ooInetHTTPProxyPort" )
296 return css::uno::Any(valueHttpProxyPort_
);
297 } else if ( PropertyName
== "ooInetHTTPSProxyName" )
299 return css::uno::Any(valueHttpsProxyName_
);
300 } else if ( PropertyName
== "ooInetHTTPSProxyPort" )
302 return css::uno::Any(valueHttpsProxyPort_
);
303 } else if ( PropertyName
== "ooInetNoProxy" )
305 return css::uno::Any(valueNoProxy_
);
306 } else if ( PropertyName
== "ooInetProxyType" )
308 return css::uno::Any(valueProxyType_
);
310 throw css::beans::UnknownPropertyException(
311 PropertyName
, getXWeak());
315 OUString SAL_CALL
WinInetBackend::getImplementationName()
317 return "com.sun.star.comp.configuration.backend.WinInetBackend" ;
320 sal_Bool SAL_CALL
WinInetBackend::supportsService(const OUString
& aServiceName
)
322 return cppu::supportsService(this, aServiceName
);
325 uno::Sequence
<OUString
> SAL_CALL
WinInetBackend::getSupportedServiceNames()
327 return { "com.sun.star.configuration.backend.WinInetBackend" };
330 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
331 shell_WinInetBackend_get_implementation(
332 css::uno::XComponentContext
* , css::uno::Sequence
<css::uno::Any
> const&)
334 return cppu::acquire(new WinInetBackend
);
338 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */