tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / ucbhelper / source / client / proxydecider.cxx
blobcfc10080529e6c802d903840ba8cb6e0649da064
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <string_view>
23 #include <utility>
24 #include <vector>
25 #include <deque>
27 #include <osl/diagnose.h>
28 #include <osl/mutex.hxx>
29 #include <rtl/ref.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>
37 #include <cppuhelper/implbase.hxx>
38 #include <ucbhelper/proxydecider.hxx>
39 #include <o3tl/string_view.hxx>
41 #ifdef _WIN32
42 #include <o3tl/char16_t2wchar_t.hxx>
43 #define WIN32_LEAN_AND_MEAN
44 #include <Windows.h>
45 #include <Winhttp.h>
46 #include <process.h>
47 #endif
49 using namespace com::sun::star;
50 using namespace ucbhelper;
52 constexpr OUString CONFIG_ROOT_KEY = u"org.openoffice.Inet/Settings"_ustr;
53 constexpr OUString PROXY_TYPE_KEY = u"ooInetProxyType"_ustr;
54 constexpr OUString NO_PROXY_LIST_KEY = u"ooInetNoProxy"_ustr;
55 constexpr OUString HTTP_PROXY_NAME_KEY = u"ooInetHTTPProxyName"_ustr;
56 constexpr OUString HTTP_PROXY_PORT_KEY = u"ooInetHTTPProxyPort"_ustr;
57 constexpr OUString HTTPS_PROXY_NAME_KEY = u"ooInetHTTPSProxyName"_ustr;
58 constexpr OUString HTTPS_PROXY_PORT_KEY = u"ooInetHTTPSProxyPort"_ustr;
61 namespace ucbhelper
65 namespace proxydecider_impl
68 namespace {
70 // A simple case ignoring wildcard matcher.
71 class WildCard
73 private:
74 OString m_aWildString;
76 public:
77 explicit WildCard( std::u16string_view rWildCard )
78 : m_aWildString(
79 OUStringToOString(
80 rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {}
82 bool Matches( std::u16string_view rStr ) const;
87 namespace {
89 class HostnameCache
91 typedef std::pair< OUString, OUString > HostListEntry;
93 std::deque< HostListEntry > m_aHostList;
95 public:
96 bool get( std::u16string_view rKey, OUString & rValue ) const
98 for (auto const& host : m_aHostList)
100 if ( host.first == rKey )
102 rValue = host.second;
103 return true;
106 return false;
109 void put( const OUString & rKey, const OUString & rValue )
111 static constexpr sal_uInt32 nCapacity = 256;
113 if ( m_aHostList.size() == nCapacity )
114 m_aHostList.resize( nCapacity / 2 );
116 m_aHostList.push_front( HostListEntry( rKey, rValue ) );
122 class InternetProxyDecider_Impl :
123 public cppu::WeakImplHelper< util::XChangesListener >
125 // see officecfg/registry/schema/org/openoffice/Inet.xcs for the definition of these values
126 enum class ProxyType { NoProxy, Automatic, Manual };
127 mutable osl::Mutex m_aMutex;
128 InternetProxyServer m_aHttpProxy;
129 InternetProxyServer m_aHttpsProxy;
130 const InternetProxyServer m_aEmptyProxy;
131 ProxyType m_nProxyType;
132 uno::Reference< util::XChangesNotifier > m_xNotifier;
133 typedef std::pair< WildCard, WildCard > NoProxyListEntry;
134 std::vector< NoProxyListEntry > m_aNoProxyList;
135 mutable HostnameCache m_aHostnames;
137 private:
138 bool shouldUseProxy( std::u16string_view rHost,
139 sal_Int32 nPort,
140 bool bUseFullyQualified ) const;
141 public:
142 explicit InternetProxyDecider_Impl(
143 const uno::Reference< uno::XComponentContext >& rxContext );
145 void dispose();
147 InternetProxyServer getProxy(const OUString& rProtocol,
148 const OUString & rHost,
149 sal_Int32 nPort ) const;
151 // XChangesListener
152 virtual void SAL_CALL changesOccurred( const util::ChangesEvent& Event ) override;
154 // XEventListener ( base of XChangesLisetenr )
155 virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
157 private:
158 void setNoProxyList( std::u16string_view rNoProxyList );
162 // WildCard Implementation.
165 bool WildCard::Matches( std::u16string_view rString ) const
167 OString aString
168 = OUStringToOString( rString, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
169 const char * pStr = aString.getStr();
170 const char * pWild = m_aWildString.getStr();
172 int pos = 0;
173 int flag = 0;
175 while ( *pWild || flag )
177 switch ( *pWild )
179 case '?':
180 if ( *pStr == '\0' )
181 return false;
182 break;
184 default:
185 if ( ( *pWild == '\\' ) && ( ( *( pWild + 1 ) == '?' )
186 || ( *( pWild + 1 ) == '*') ) )
187 pWild++;
188 if ( *pWild != *pStr )
189 if ( !pos )
190 return false;
191 else
192 pWild += pos;
193 else
194 break;
196 [[fallthrough]];
198 case '*':
199 while ( *pWild == '*' )
200 pWild++;
201 if ( *pWild == '\0' )
202 return true;
203 flag = 1;
204 pos = 0;
205 if ( *pStr == '\0' )
206 return ( *pWild == '\0' );
207 while ( *pStr && *pStr != *pWild )
209 if ( *pWild == '?' ) {
210 pWild++;
211 while ( *pWild == '*' )
212 pWild++;
214 pStr++;
215 if ( *pStr == '\0' )
216 return ( *pWild == '\0' );
218 break;
220 if ( *pWild != '\0' )
221 pWild++;
222 if ( *pStr != '\0' )
223 pStr++;
224 else
225 flag = 0;
226 if ( flag )
227 pos--;
229 return ( *pStr == '\0' ) && ( *pWild == '\0' );
233 static bool getConfigStringValue(
234 const uno::Reference< container::XNameAccess > & xNameAccess,
235 const OUString& key,
236 OUString & value )
240 if ( !( xNameAccess->getByName( key ) >>= value ) )
242 OSL_FAIL( "InternetProxyDecider - "
243 "Error getting config item value!" );
244 return false;
247 catch ( lang::WrappedTargetException const & )
249 return false;
251 catch ( container::NoSuchElementException const & )
253 return false;
255 return true;
259 static bool getConfigInt32Value(
260 const uno::Reference< container::XNameAccess > & xNameAccess,
261 const OUString& key,
262 sal_Int32 & value )
266 uno::Any aValue = xNameAccess->getByName( key );
267 if ( aValue.hasValue() && !( aValue >>= value ) )
269 OSL_FAIL( "InternetProxyDecider - "
270 "Error getting config item value!" );
271 return false;
274 catch ( lang::WrappedTargetException const & )
276 return false;
278 catch ( container::NoSuchElementException const & )
280 return false;
282 return true;
286 // InternetProxyDecider_Impl Implementation.
289 InternetProxyDecider_Impl::InternetProxyDecider_Impl(
290 const uno::Reference< uno::XComponentContext >& rxContext )
291 : m_nProxyType( ProxyType::NoProxy ),
292 m_aHostnames()
297 // Read proxy configuration from config db.
300 uno::Reference< lang::XMultiServiceFactory > xConfigProv =
301 configuration::theDefaultProvider::get( rxContext );
303 uno::Sequence< uno::Any > aArguments{ uno::Any(CONFIG_ROOT_KEY) };
304 uno::Reference< uno::XInterface > xInterface(
305 xConfigProv->createInstanceWithArguments(
306 u"com.sun.star.configuration.ConfigurationAccess"_ustr,
307 aArguments ) );
309 OSL_ENSURE( xInterface.is(),
310 "InternetProxyDecider - No config access!" );
312 if ( xInterface.is() )
314 uno::Reference< container::XNameAccess > xNameAccess(
315 xInterface, uno::UNO_QUERY );
316 OSL_ENSURE( xNameAccess.is(),
317 "InternetProxyDecider - No name access!" );
319 if ( xNameAccess.is() )
321 // *** Proxy type ***
322 sal_Int32 tmp = 0;
323 getConfigInt32Value(
324 xNameAccess, PROXY_TYPE_KEY, tmp );
325 m_nProxyType = static_cast<ProxyType>(tmp);
327 // *** No proxy list ***
328 OUString aNoProxyList;
329 getConfigStringValue(
330 xNameAccess, NO_PROXY_LIST_KEY, aNoProxyList );
331 setNoProxyList( aNoProxyList );
333 // *** HTTP ***
334 getConfigStringValue(
335 xNameAccess, HTTP_PROXY_NAME_KEY, m_aHttpProxy.aName );
337 m_aHttpProxy.nPort = -1;
338 getConfigInt32Value(
339 xNameAccess, HTTP_PROXY_PORT_KEY, m_aHttpProxy.nPort );
340 if ( m_aHttpProxy.nPort == -1 )
341 m_aHttpProxy.nPort = 80; // standard HTTP port.
343 // *** HTTPS ***
344 getConfigStringValue(
345 xNameAccess, HTTPS_PROXY_NAME_KEY, m_aHttpsProxy.aName );
347 m_aHttpsProxy.nPort = -1;
348 getConfigInt32Value(
349 xNameAccess, HTTPS_PROXY_PORT_KEY, m_aHttpsProxy.nPort );
350 if ( m_aHttpsProxy.nPort == -1 )
351 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
354 // Register as listener for config changes.
356 m_xNotifier.set( xInterface, uno::UNO_QUERY );
358 OSL_ENSURE( m_xNotifier.is(),
359 "InternetProxyDecider - No notifier!" );
361 if ( m_xNotifier.is() )
362 m_xNotifier->addChangesListener( this );
365 catch ( uno::Exception const & )
367 // createInstance, createInstanceWithArguments
368 OSL_FAIL( "InternetProxyDecider - Exception!" );
372 void InternetProxyDecider_Impl::dispose()
374 uno::Reference< util::XChangesNotifier > xNotifier;
376 if ( m_xNotifier.is() )
378 osl::Guard< osl::Mutex > aGuard( m_aMutex );
380 if ( m_xNotifier.is() )
382 xNotifier = m_xNotifier;
383 m_xNotifier.clear();
387 // Do this unguarded!
388 if ( xNotifier.is() )
389 xNotifier->removeChangesListener( this );
393 bool InternetProxyDecider_Impl::shouldUseProxy( std::u16string_view rHost,
394 sal_Int32 nPort,
395 bool bUseFullyQualified ) const
397 OUStringBuffer aBuffer;
399 if ( ( rHost.find( ':' ) != std::u16string_view::npos ) &&
400 ( rHost[ 0 ] != '[' ) )
402 // host is given as numeric IPv6 address
403 aBuffer.append( OUString::Concat("[") + rHost + "]" );
405 else
407 // host is given either as numeric IPv4 address or non-numeric hostname
408 aBuffer.append( rHost );
411 aBuffer.append( ":" + OUString::number( nPort ) );
413 for (auto const& noProxy : m_aNoProxyList)
415 if ( bUseFullyQualified )
417 if ( noProxy.second.Matches( aBuffer ) )
418 return false;
420 else
422 if ( noProxy.first.Matches( aBuffer ) )
423 return false;
427 return true;
430 namespace
432 #ifdef _WIN32
433 struct GetPACProxyData
435 const OUString& m_rProtocol;
436 const OUString& m_rHost;
437 sal_Int32 m_nPort;
438 bool m_bAutoDetect = false;
439 OUString m_sAutoConfigUrl;
440 InternetProxyServer m_ProxyServer;
442 GetPACProxyData(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
443 : m_rProtocol(rProtocol)
444 , m_rHost(rHost)
445 , m_nPort(nPort)
450 // Tries to get proxy configuration using WinHttpGetProxyForUrl, which supports Web Proxy Auto-Discovery
451 // (WPAD) protocol and manually configured address to get Proxy Auto-Configuration (PAC) file.
452 // The WinINet/WinHTTP functions cannot correctly run in a STA COM thread, so use a dedicated thread
453 unsigned __stdcall GetPACProxyThread(void* lpParameter)
455 assert(lpParameter);
456 GetPACProxyData* pData = static_cast<GetPACProxyData*>(lpParameter);
458 OUString url(pData->m_rProtocol + "://" + pData->m_rHost + ":"
459 + OUString::number(pData->m_nPort));
461 HINTERNET hInternet = WinHttpOpen(L"Mozilla 5.0", WINHTTP_ACCESS_TYPE_NO_PROXY,
462 WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
463 DWORD nError = GetLastError();
464 if (!hInternet)
465 return nError;
467 WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions{};
468 if (pData->m_bAutoDetect)
470 AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
471 AutoProxyOptions.dwAutoDetectFlags
472 = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
474 if (!pData->m_sAutoConfigUrl.isEmpty())
476 AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
477 AutoProxyOptions.lpszAutoConfigUrl = o3tl::toW(pData->m_sAutoConfigUrl.getStr());
479 // First, try without autologon. According to
480 // https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/web/winhttp/WinhttpProxySample/GetProxy.cpp
481 // autologon prevents caching, and so causes repetitive network traffic.
482 AutoProxyOptions.fAutoLogonIfChallenged = FALSE;
483 WINHTTP_PROXY_INFO ProxyInfo{};
484 bool bResult
485 = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()), &AutoProxyOptions, &ProxyInfo);
486 nError = GetLastError();
487 if (!bResult && nError == ERROR_WINHTTP_LOGIN_FAILURE)
489 AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
490 bResult = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()),
491 &AutoProxyOptions, &ProxyInfo);
492 nError = GetLastError();
494 WinHttpCloseHandle(hInternet);
495 if (bResult)
497 if (ProxyInfo.lpszProxyBypass)
498 GlobalFree(ProxyInfo.lpszProxyBypass);
499 if (ProxyInfo.lpszProxy)
501 OUString sProxyResult(o3tl::toU(ProxyInfo.lpszProxy));
502 GlobalFree(ProxyInfo.lpszProxy);
503 // Get the first of possibly multiple results
504 sProxyResult = sProxyResult.getToken(0, ';');
505 sal_Int32 nPortSepPos = sProxyResult.indexOf(':');
506 if (nPortSepPos != -1)
508 pData->m_ProxyServer.nPort = o3tl::toInt32(sProxyResult.subView(nPortSepPos + 1));
509 sProxyResult = sProxyResult.copy(0, nPortSepPos);
511 else
513 pData->m_ProxyServer.nPort = 0;
515 pData->m_ProxyServer.aName = sProxyResult;
519 return nError;
522 InternetProxyServer GetPACProxy(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
524 GetPACProxyData aData(rProtocol, rHost, nPort);
526 // WinHTTP only supports http(s), so don't try for other protocols
527 if (!(rProtocol.equalsIgnoreAsciiCase("http") || rProtocol.equalsIgnoreAsciiCase("https")))
528 return aData.m_ProxyServer;
530 // Only try to get configuration from PAC (with all the overhead, including new thread)
531 // if configured to do so
533 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG aProxyConfig{};
534 bool bResult = WinHttpGetIEProxyConfigForCurrentUser(&aProxyConfig);
535 if (aProxyConfig.lpszProxy)
536 GlobalFree(aProxyConfig.lpszProxy);
537 if (aProxyConfig.lpszProxyBypass)
538 GlobalFree(aProxyConfig.lpszProxyBypass);
539 // Don't try WPAD if AutoDetection or AutoConfig script URL are not configured
540 if (!bResult || !(aProxyConfig.fAutoDetect || aProxyConfig.lpszAutoConfigUrl))
541 return aData.m_ProxyServer;
542 aData.m_bAutoDetect = aProxyConfig.fAutoDetect;
543 if (aProxyConfig.lpszAutoConfigUrl)
545 aData.m_sAutoConfigUrl = o3tl::toU(aProxyConfig.lpszAutoConfigUrl);
546 GlobalFree(aProxyConfig.lpszAutoConfigUrl);
550 HANDLE hThread = reinterpret_cast<HANDLE>(
551 _beginthreadex(nullptr, 0, GetPACProxyThread, &aData, 0, nullptr));
552 if (hThread)
554 WaitForSingleObject(hThread, INFINITE);
555 CloseHandle(hThread);
557 return aData.m_ProxyServer;
560 #else // .. _WIN32
562 // Read the settings from the OS which are stored in env vars
564 InternetProxyServer GetUnixSystemProxy(const OUString & rProtocol)
566 // TODO this could be improved to read the "no_proxy" env variable
567 InternetProxyServer aProxy;
568 OUString protocolLower = rProtocol.toAsciiLowerCase() + "_proxy";
569 OString protocolLowerStr = OUStringToOString( protocolLower, RTL_TEXTENCODING_ASCII_US );
570 const char* pEnvProxy = getenv(protocolLowerStr.getStr());
571 if (!pEnvProxy)
572 return aProxy;
573 // expecting something like "https://example.ct:80"
574 OUString tmp = OUString::createFromAscii(pEnvProxy);
575 if (tmp.getLength() < (rProtocol.getLength() + 3))
576 return aProxy;
577 sal_Int32 x = tmp.indexOf("://");
578 sal_Int32 at = tmp.indexOf('@', x == -1 ? 0 : x + 3);
579 x = tmp.indexOf(':', at == -1 ? x == -1 ? 0 : x + 3 : at + 1);
580 if (x == -1)
581 return aProxy;
582 int nPort = o3tl::toInt32(tmp.subView(x + 1));
583 if (nPort == 0)
584 return aProxy;
585 aProxy.aName = tmp.copy(0, x);
586 aProxy.nPort = nPort;
587 return aProxy;
590 #endif // else .. _WIN32
593 InternetProxyServer InternetProxyDecider_Impl::getProxy(
594 const OUString & rProtocol,
595 const OUString & rHost,
596 sal_Int32 nPort ) const
598 osl::Guard< osl::Mutex > aGuard( m_aMutex );
600 if ( m_nProxyType == ProxyType::NoProxy )
602 // Never use proxy.
603 return m_aEmptyProxy;
606 // If get from system
607 if (m_nProxyType == ProxyType::Automatic && !rHost.isEmpty())
609 #ifdef _WIN32
610 InternetProxyServer aProxy(GetPACProxy(rProtocol, rHost, nPort));
611 #else
612 InternetProxyServer aProxy(GetUnixSystemProxy(rProtocol));
613 #endif // _WIN32
614 if (!aProxy.aName.isEmpty())
615 return aProxy;
618 if ( !rHost.isEmpty() && !m_aNoProxyList.empty() )
621 // First, try direct hostname match - #110515#
624 if ( !shouldUseProxy( rHost, nPort, false ) )
625 return m_aEmptyProxy;
628 // Second, try match against full qualified hostname - #104401#
631 OUString aHost;
633 if ( ( rHost.getLength() > 1 ) &&
634 ( rHost[ 0 ] == '[' ))
636 // host is given as numeric IPv6 address. name resolution
637 // functions need hostname without square brackets.
638 aHost = rHost.copy( 1, rHost.getLength() - 2 );
640 else
642 aHost = rHost;
645 OUString aFullyQualifiedHost;
646 if ( !m_aHostnames.get( aHost, aFullyQualifiedHost ) )
648 // This might be quite expensive (DNS lookup).
649 const osl::SocketAddr aAddr( aHost, nPort );
650 aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase();
651 m_aHostnames.put( aHost, aFullyQualifiedHost );
654 // Error resolving name? -> fallback.
655 if ( aFullyQualifiedHost.isEmpty() )
656 aFullyQualifiedHost = aHost;
658 if ( aFullyQualifiedHost != aHost )
660 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, false ) )
661 return m_aEmptyProxy;
665 // Third, try match of fully qualified entries in no-proxy list
666 // against full qualified hostname
668 // Example:
669 // list: staroffice-doc -> full: xyz.germany.sun.com
670 // in: staroffice-doc.germany.sun.com -> full: xyz.germany.sun.com
673 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, true ) )
674 return m_aEmptyProxy;
677 if (rProtocol.toAsciiLowerCase() == "https")
679 if ( !m_aHttpsProxy.aName.isEmpty() )
680 return m_aHttpsProxy;
682 else if ( !m_aHttpProxy.aName.isEmpty() )
684 // All other protocols use the HTTP proxy.
685 return m_aHttpProxy;
687 return m_aEmptyProxy;
690 // virtual
691 void SAL_CALL InternetProxyDecider_Impl::changesOccurred(
692 const util::ChangesEvent& Event )
694 osl::Guard< osl::Mutex > aGuard( m_aMutex );
696 for ( const util::ElementChange& rElem : Event.Changes )
698 OUString aKey;
699 if ( ( rElem.Accessor >>= aKey ) && !aKey.isEmpty() )
701 if ( aKey == PROXY_TYPE_KEY )
703 sal_Int32 tmp;
704 if ( !( rElem.Element >>= tmp ) )
706 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
707 "Error getting config item value!" );
709 else
710 m_nProxyType = static_cast<ProxyType>(tmp);
712 else if ( aKey == NO_PROXY_LIST_KEY )
714 OUString aNoProxyList;
715 if ( !( rElem.Element >>= aNoProxyList ) )
717 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
718 "Error getting config item value!" );
721 setNoProxyList( aNoProxyList );
723 else if ( aKey == HTTP_PROXY_NAME_KEY )
725 if ( !( rElem.Element >>= m_aHttpProxy.aName ) )
727 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
728 "Error getting config item value!" );
731 else if ( aKey == HTTP_PROXY_PORT_KEY )
733 if ( !( rElem.Element >>= m_aHttpProxy.nPort ) )
735 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
736 "Error getting config item value!" );
739 if ( m_aHttpProxy.nPort == -1 )
740 m_aHttpProxy.nPort = 80; // standard HTTP port.
742 else if ( aKey == HTTPS_PROXY_NAME_KEY )
744 if ( !( rElem.Element >>= m_aHttpsProxy.aName ) )
746 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
747 "Error getting config item value!" );
750 else if ( aKey == HTTPS_PROXY_PORT_KEY )
752 if ( !( rElem.Element >>= m_aHttpsProxy.nPort ) )
754 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
755 "Error getting config item value!" );
758 if ( m_aHttpsProxy.nPort == -1 )
759 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
766 // virtual
767 void SAL_CALL InternetProxyDecider_Impl::disposing(const lang::EventObject&)
769 if ( m_xNotifier.is() )
771 osl::Guard< osl::Mutex > aGuard( m_aMutex );
773 if ( m_xNotifier.is() )
774 m_xNotifier.clear();
779 void InternetProxyDecider_Impl::setNoProxyList(
780 std::u16string_view rNoProxyList )
782 osl::Guard< osl::Mutex > aGuard( m_aMutex );
784 m_aNoProxyList.clear();
786 if ( rNoProxyList.empty() )
787 return;
789 // List of connection endpoints hostname[:port],
790 // separated by semicolon. Wildcards allowed.
792 size_t nPos = 0;
793 size_t nEnd = rNoProxyList.find( ';' );
794 size_t nLen = rNoProxyList.size();
798 if ( nEnd == std::u16string_view::npos )
799 nEnd = nLen;
801 OUString aToken( rNoProxyList.substr( nPos, nEnd - nPos ) );
803 if ( !aToken.isEmpty() )
805 OUString aServer;
806 OUString aPort;
808 // numerical IPv6 address?
809 bool bIPv6Address = false;
810 sal_Int32 nClosedBracketPos = aToken.indexOf( ']' );
811 if ( nClosedBracketPos == -1 )
812 nClosedBracketPos = 0;
813 else
814 bIPv6Address = true;
816 sal_Int32 nColonPos = aToken.indexOf( ':', nClosedBracketPos );
817 if ( nColonPos == -1 )
819 // No port given, server pattern equals current token
820 aPort = "*";
821 if ( aToken.indexOf( '*' ) == -1 )
823 // pattern describes exactly one server
824 aServer = aToken;
827 aToken += ":*";
829 else
831 // Port given, extract server pattern
832 sal_Int32 nAsteriskPos = aToken.indexOf( '*' );
833 aPort = aToken.copy( nColonPos + 1 );
834 if ( nAsteriskPos < nColonPos )
836 // pattern describes exactly one server
837 aServer = aToken.copy( 0, nColonPos );
841 OUStringBuffer aFullyQualifiedHost;
842 if ( !aServer.isEmpty() )
844 // Remember fully qualified server name if current list
845 // entry specifies exactly one non-fully qualified server
846 // name.
848 // remove square brackets from host name in case it's
849 // a numerical IPv6 address.
850 if ( bIPv6Address )
851 aServer = aServer.copy( 1, aServer.getLength() - 2 );
853 // This might be quite expensive (DNS lookup).
854 const osl::SocketAddr aAddr( aServer, 0 );
855 OUString aTmp = aAddr.getHostname().toAsciiLowerCase();
856 if ( aTmp != aServer.toAsciiLowerCase() )
858 if ( bIPv6Address )
859 aFullyQualifiedHost.append( "[" + aTmp + "]" );
860 else
861 aFullyQualifiedHost.append( aTmp );
862 aFullyQualifiedHost.append( ":" + aPort );
866 m_aNoProxyList.emplace_back( WildCard( aToken ),
867 WildCard( aFullyQualifiedHost ) );
870 if ( nEnd != nLen )
872 nPos = nEnd + 1;
873 nEnd = rNoProxyList.find( ';', nPos );
876 while ( nEnd != nLen );
879 } // namespace proxydecider_impl
882 // InternetProxyDecider Implementation.
885 InternetProxyDecider::InternetProxyDecider(
886 const uno::Reference< uno::XComponentContext>& rxContext )
887 : m_xImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxContext ) )
892 InternetProxyDecider::~InternetProxyDecider()
894 // Break circular reference between config listener and notifier.
895 m_xImpl->dispose();
899 OUString InternetProxyDecider::getProxy(
900 const OUString & rProtocol,
901 const OUString & rHost,
902 sal_Int32 nPort ) const
904 InternetProxyServer ret(m_xImpl->getProxy(rProtocol, rHost, nPort));
906 if (ret.aName.isEmpty() || ret.nPort == -1)
908 return ret.aName;
911 return ret.aName + ":" + OUString::number(ret.nPort);
914 } // namespace ucbhelper
916 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */