27#include <osl/diagnose.h>
28#include <osl/mutex.hxx>
30#include <osl/socket.hxx>
31#include <rtl/ustrbuf.hxx>
32#include <com/sun/star/container/XNameAccess.hpp>
33#include <com/sun/star/configuration/theDefaultProvider.hpp>
34#include <com/sun/star/lang/XMultiServiceFactory.hpp>
35#include <com/sun/star/util/XChangesListener.hpp>
36#include <com/sun/star/util/XChangesNotifier.hpp>
43#define WIN32_LEAN_AND_MEAN
66namespace proxydecider_impl
78 explicit WildCard( std::u16string_view rWildCard )
81 rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {}
83 bool Matches( std::u16string_view rStr )
const;
92 typedef std::pair< OUString, OUString > HostListEntry;
97 bool get( std::u16string_view rKey, OUString & rValue )
const
101 if ( host.first == rKey )
103 rValue = host.second;
110 void put(
const OUString & rKey,
const OUString & rValue )
112 static constexpr sal_uInt32 nCapacity = 256;
117 m_aHostList.push_front( HostListEntry( rKey, rValue ) );
124 public cppu::WeakImplHelper< util::XChangesListener >
142 bool bUseFullyQualified )
const;
145 const uno::Reference< uno::XComponentContext >& rxContext );
150 const OUString & rHost,
151 sal_Int32 nPort )
const;
154 virtual void SAL_CALL
changesOccurred(
const util::ChangesEvent& Event )
override;
157 virtual void SAL_CALL
disposing(
const lang::EventObject& Source )
override;
171 const char * pStr = aString.getStr();
177 while ( *pWild || flag )
187 if ( ( *pWild ==
'\\' ) && ( ( *( pWild + 1 ) ==
'?' )
188 || ( *( pWild + 1 ) ==
'*') ) )
190 if ( *pWild != *pStr )
201 while ( *pWild ==
'*' )
203 if ( *pWild ==
'\0' )
208 return ( *pWild ==
'\0' );
209 while ( *pStr && *pStr != *pWild )
211 if ( *pWild ==
'?' ) {
213 while ( *pWild ==
'*' )
218 return ( *pWild ==
'\0' );
222 if ( *pWild !=
'\0' )
231 return ( *pStr ==
'\0' ) && ( *pWild ==
'\0' );
236 const uno::Reference< container::XNameAccess > & xNameAccess,
242 if ( !( xNameAccess->getByName( key ) >>=
value ) )
244 OSL_FAIL(
"InternetProxyDecider - "
245 "Error getting config item value!" );
249 catch ( lang::WrappedTargetException
const & )
253 catch ( container::NoSuchElementException
const & )
262 const uno::Reference< container::XNameAccess > & xNameAccess,
268 uno::Any aValue = xNameAccess->getByName( key );
271 OSL_FAIL(
"InternetProxyDecider - "
272 "Error getting config item value!" );
276 catch ( lang::WrappedTargetException
const & )
280 catch ( container::NoSuchElementException
const & )
292 const uno::Reference< uno::XComponentContext >& rxContext )
302 uno::Reference< lang::XMultiServiceFactory > xConfigProv =
303 configuration::theDefaultProvider::get( rxContext );
306 uno::Reference< uno::XInterface > xInterface(
307 xConfigProv->createInstanceWithArguments(
308 "com.sun.star.configuration.ConfigurationAccess",
311 OSL_ENSURE( xInterface.is(),
312 "InternetProxyDecider - No config access!" );
314 if ( xInterface.is() )
316 uno::Reference< container::XNameAccess > xNameAccess(
317 xInterface, uno::UNO_QUERY );
318 OSL_ENSURE( xNameAccess.is(),
319 "InternetProxyDecider - No name access!" );
321 if ( xNameAccess.is() )
330 OUString aNoProxyList;
369 "InternetProxyDecider - No notifier!" );
375 catch ( uno::Exception
const & )
378 OSL_FAIL(
"InternetProxyDecider - Exception!" );
384 uno::Reference< util::XChangesNotifier > xNotifier;
388 osl::Guard< osl::Mutex > aGuard(
m_aMutex );
398 if ( xNotifier.is() )
399 xNotifier->removeChangesListener(
this );
405 bool bUseFullyQualified )
const
409 if ( ( rHost.find(
':' ) != std::u16string_view::npos ) &&
410 ( rHost[ 0 ] !=
'[' ) )
413 aBuffer.append( OUString::Concat(
"[") + rHost +
"]" );
421 aBuffer.append(
":" + OUString::number( nPort ) );
425 if ( bUseFullyQualified )
427 if ( noProxy.second.Matches(
aBuffer ) )
432 if ( noProxy.first.Matches(
aBuffer ) )
443struct GetPACProxyData
445 const OUString& m_rProtocol;
446 const OUString& m_rHost;
448 bool m_bAutoDetect =
false;
449 OUString m_sAutoConfigUrl;
452 GetPACProxyData(
const OUString& rProtocol,
const OUString& rHost, sal_Int32 nPort)
453 : m_rProtocol(rProtocol)
463DWORD WINAPI GetPACProxyThread(_In_ LPVOID lpParameter)
466 GetPACProxyData*
pData =
static_cast<GetPACProxyData*
>(lpParameter);
468 OUString url(
pData->m_rProtocol +
"://" +
pData->m_rHost +
":"
469 + OUString::number(
pData->m_nPort));
471 HINTERNET hInternet = WinHttpOpen(L
"Mozilla 5.0", WINHTTP_ACCESS_TYPE_NO_PROXY,
472 WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
473 DWORD nError = GetLastError();
477 WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions{};
478 if (
pData->m_bAutoDetect)
480 AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
481 AutoProxyOptions.dwAutoDetectFlags
482 = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
484 if (!
pData->m_sAutoConfigUrl.isEmpty())
486 AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
487 AutoProxyOptions.lpszAutoConfigUrl = o3tl::toW(
pData->m_sAutoConfigUrl.getStr());
492 AutoProxyOptions.fAutoLogonIfChallenged =
FALSE;
493 WINHTTP_PROXY_INFO ProxyInfo{};
495 = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()), &AutoProxyOptions, &ProxyInfo);
496 nError = GetLastError();
497 if (!bResult && nError == ERROR_WINHTTP_LOGIN_FAILURE)
499 AutoProxyOptions.fAutoLogonIfChallenged =
TRUE;
500 bResult = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()),
501 &AutoProxyOptions, &ProxyInfo);
502 nError = GetLastError();
504 WinHttpCloseHandle(hInternet);
507 if (ProxyInfo.lpszProxyBypass)
508 GlobalFree(ProxyInfo.lpszProxyBypass);
509 if (ProxyInfo.lpszProxy)
511 OUString sProxyResult(o3tl::toU(ProxyInfo.lpszProxy));
512 GlobalFree(ProxyInfo.lpszProxy);
514 sProxyResult = sProxyResult.getToken(0,
';');
515 sal_Int32 nPortSepPos = sProxyResult.indexOf(
':');
516 if (nPortSepPos != -1)
519 sProxyResult = sProxyResult.copy(0, nPortSepPos);
523 pData->m_ProxyServer.nPort = 0;
525 pData->m_ProxyServer.aName = sProxyResult;
532InternetProxyServer GetPACProxy(
const OUString& rProtocol,
const OUString& rHost, sal_Int32 nPort)
534 GetPACProxyData
aData(rProtocol, rHost, nPort);
537 if (!(rProtocol.equalsIgnoreAsciiCase(
"http") || rProtocol.equalsIgnoreAsciiCase(
"https")))
538 return aData.m_ProxyServer;
543 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG aProxyConfig{};
544 bool bResult = WinHttpGetIEProxyConfigForCurrentUser(&aProxyConfig);
545 if (aProxyConfig.lpszProxy)
546 GlobalFree(aProxyConfig.lpszProxy);
547 if (aProxyConfig.lpszProxyBypass)
548 GlobalFree(aProxyConfig.lpszProxyBypass);
550 if (!bResult || !(aProxyConfig.fAutoDetect || aProxyConfig.lpszAutoConfigUrl))
551 return aData.m_ProxyServer;
552 aData.m_bAutoDetect = aProxyConfig.fAutoDetect;
553 if (aProxyConfig.lpszAutoConfigUrl)
555 aData.m_sAutoConfigUrl = o3tl::toU(aProxyConfig.lpszAutoConfigUrl);
556 GlobalFree(aProxyConfig.lpszAutoConfigUrl);
560 HANDLE hThread = CreateThread(
nullptr, 0, GetPACProxyThread, &aData, 0,
nullptr);
563 WaitForSingleObject(hThread, INFINITE);
564 CloseHandle(hThread);
566 return aData.m_ProxyServer;
577 OUString protocolLower = rProtocol.toAsciiLowerCase() +
"_proxy";
578 OString protocolLowerStr =
OUStringToOString( protocolLower, RTL_TEXTENCODING_ASCII_US );
579 const char* pEnvProxy = getenv(protocolLowerStr.getStr());
583 OUString tmp = OUString::createFromAscii(pEnvProxy);
584 if (tmp.getLength() < (rProtocol.getLength() + 3))
586 tmp = tmp.copy(rProtocol.getLength() + 3);
587 sal_Int32
x = tmp.indexOf(
':');
593 aProxy.
aName = tmp.copy(0, x);
594 aProxy.
nPort = nPort;
602 const OUString & rProtocol,
603 const OUString & rHost,
604 sal_Int32 nPort )
const
606 osl::Guard< osl::Mutex > aGuard(
m_aMutex );
622 if (!aProxy.
aName.isEmpty())
641 if ( ( rHost.getLength() > 1 ) &&
642 ( rHost[ 0 ] ==
'[' ))
646 aHost = rHost.copy( 1, rHost.getLength() - 2 );
653 OUString aFullyQualifiedHost;
657 const osl::SocketAddr aAddr( aHost, nPort );
658 aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase();
663 if ( aFullyQualifiedHost.isEmpty() )
664 aFullyQualifiedHost = aHost;
666 if ( aFullyQualifiedHost != aHost )
685 if ( rProtocol.toAsciiLowerCase() ==
"ftp" )
690 else if ( rProtocol.toAsciiLowerCase() ==
"https" )
705 const util::ChangesEvent& Event )
707 osl::Guard< osl::Mutex > aGuard(
m_aMutex );
709 for (
const util::ElementChange& rElem : Event.Changes )
712 if ( ( rElem.Accessor >>= aKey ) && !aKey.isEmpty() )
717 if ( !( rElem.Element >>= tmp ) )
719 OSL_FAIL(
"InternetProxyDecider - changesOccurred - "
720 "Error getting config item value!" );
727 OUString aNoProxyList;
728 if ( !( rElem.Element >>= aNoProxyList ) )
730 OSL_FAIL(
"InternetProxyDecider - changesOccurred - "
731 "Error getting config item value!" );
740 OSL_FAIL(
"InternetProxyDecider - changesOccurred - "
741 "Error getting config item value!" );
748 OSL_FAIL(
"InternetProxyDecider - changesOccurred - "
749 "Error getting config item value!" );
759 OSL_FAIL(
"InternetProxyDecider - changesOccurred - "
760 "Error getting config item value!" );
767 OSL_FAIL(
"InternetProxyDecider - changesOccurred - "
768 "Error getting config item value!" );
778 OSL_FAIL(
"InternetProxyDecider - changesOccurred - "
779 "Error getting config item value!" );
786 OSL_FAIL(
"InternetProxyDecider - changesOccurred - "
787 "Error getting config item value!" );
800 osl::Guard< osl::Mutex > aGuard(
m_aMutex );
809 const OUString & rNoProxyList )
811 osl::Guard< osl::Mutex > aGuard(
m_aMutex );
815 if ( rNoProxyList.isEmpty() )
822 sal_Int32 nEnd = rNoProxyList.indexOf(
';' );
823 sal_Int32 nLen = rNoProxyList.getLength();
830 OUString aToken = rNoProxyList.copy(
nPos, nEnd -
nPos );
832 if ( !aToken.isEmpty() )
838 bool bIPv6Address =
false;
839 sal_Int32 nClosedBracketPos = aToken.indexOf(
']' );
840 if ( nClosedBracketPos == -1 )
841 nClosedBracketPos = 0;
845 sal_Int32 nColonPos = aToken.indexOf(
':', nClosedBracketPos );
846 if ( nColonPos == -1 )
850 if ( aToken.indexOf(
'*' ) == -1 )
861 sal_Int32 nAsteriskPos = aToken.indexOf(
'*' );
862 aPort = aToken.copy( nColonPos + 1 );
863 if ( nAsteriskPos < nColonPos )
866 aServer = aToken.copy( 0, nColonPos );
870 OUStringBuffer aFullyQualifiedHost;
871 if ( !aServer.isEmpty() )
880 aServer = aServer.copy( 1, aServer.getLength() - 2 );
883 const osl::SocketAddr aAddr( aServer, 0 );
884 OUString aTmp = aAddr.getHostname().toAsciiLowerCase();
885 if ( aTmp != aServer.toAsciiLowerCase() )
888 aFullyQualifiedHost.append(
"[" + aTmp +
"]" );
890 aFullyQualifiedHost.append( aTmp );
891 aFullyQualifiedHost.append(
":" + aPort );
896 WildCard( aFullyQualifiedHost ) );
902 nEnd = rNoProxyList.indexOf(
';',
nPos );
905 while ( nEnd != nLen );
915 const uno::Reference< uno::XComponentContext>& rxContext )
916: m_xImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxContext ) )
929 const OUString & rHost,
930 sal_Int32 nPort )
const
935 return !rData.
aName.isEmpty();
940 const OUString & rProtocol,
941 const OUString & rHost,
942 sal_Int32 nPort )
const
944 return m_xImpl->getProxy( rProtocol, rHost, nPort );
bool Matches(std::u16string_view rStr) const
InternetProxyServer getProxy(const OUString &rProtocol, const OUString &rHost, sal_Int32 nPort) const
Returns the proxy server to be used.
rtl::Reference< proxydecider_impl::InternetProxyDecider_Impl > m_xImpl
InternetProxyDecider(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
Constructor.
~InternetProxyDecider()
Destructor.
bool shouldUseProxy(const OUString &rProtocol, const OUString &rHost, sal_Int32 nPort) const
Informs whether a proxy server should be used.
InternetProxyServer m_aFtpProxy
std::vector< NoProxyListEntry > m_aNoProxyList
void setNoProxyList(const OUString &rNoProxyList)
HostnameCache m_aHostnames
InternetProxyServer getProxy(const OUString &rProtocol, const OUString &rHost, sal_Int32 nPort) const
InternetProxyServer m_aHttpProxy
bool shouldUseProxy(std::u16string_view rHost, sal_Int32 nPort, bool bUseFullyQualified) const
InternetProxyDecider_Impl(const uno::Reference< uno::XComponentContext > &rxContext)
const InternetProxyServer m_aEmptyProxy
virtual void SAL_CALL disposing(const lang::EventObject &Source) override
InternetProxyServer m_aHttpsProxy
uno::Reference< util::XChangesNotifier > m_xNotifier
virtual void SAL_CALL changesOccurred(const util::ChangesEvent &Event) override
std::pair< WildCard, WildCard > NoProxyListEntry
Sequence< PropertyValue > aArguments
std::unique_ptr< sal_Int32[]> pData
constexpr OUStringLiteral aData
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
static bool getConfigInt32Value(const uno::Reference< container::XNameAccess > &xNameAccess, const OUString &key, sal_Int32 &value)
static bool getConfigStringValue(const uno::Reference< container::XNameAccess > &xNameAccess, const OUString &key, OUString &value)
constexpr OUStringLiteral NO_PROXY_LIST_KEY
constexpr OUStringLiteral HTTPS_PROXY_PORT_KEY
constexpr OUStringLiteral HTTP_PROXY_NAME_KEY
constexpr OUStringLiteral PROXY_TYPE_KEY
constexpr OUStringLiteral FTP_PROXY_NAME_KEY
constexpr OUStringLiteral FTP_PROXY_PORT_KEY
constexpr OUStringLiteral HTTP_PROXY_PORT_KEY
constexpr OUStringLiteral HTTPS_PROXY_NAME_KEY
constexpr OUStringLiteral CONFIG_ROOT_KEY
std::deque< HostListEntry > m_aHostList
This struct describes a proxy server.
sal_Int32 nPort
The port of the proxy server.
OUString aName
The name of the proxy server.
std::unique_ptr< char[]> aBuffer