calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / ucbhelper / source / client / proxydecider.cxx
blob10228b72aedcb8e91f9e1de3c48f87687a2b9c4e
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 #endif
48 using namespace com::sun::star;
49 using namespace ucbhelper;
51 constexpr OUStringLiteral CONFIG_ROOT_KEY = u"org.openoffice.Inet/Settings";
52 constexpr OUStringLiteral PROXY_TYPE_KEY = u"ooInetProxyType";
53 constexpr OUStringLiteral NO_PROXY_LIST_KEY = u"ooInetNoProxy";
54 constexpr OUStringLiteral HTTP_PROXY_NAME_KEY = u"ooInetHTTPProxyName";
55 constexpr OUStringLiteral HTTP_PROXY_PORT_KEY = u"ooInetHTTPProxyPort";
56 constexpr OUStringLiteral HTTPS_PROXY_NAME_KEY = u"ooInetHTTPSProxyName";
57 constexpr OUStringLiteral HTTPS_PROXY_PORT_KEY = u"ooInetHTTPSProxyPort";
58 constexpr OUStringLiteral FTP_PROXY_NAME_KEY = u"ooInetFTPProxyName";
59 constexpr OUStringLiteral FTP_PROXY_PORT_KEY = u"ooInetFTPProxyPort";
62 namespace ucbhelper
66 namespace proxydecider_impl
69 namespace {
71 // A simple case ignoring wildcard matcher.
72 class WildCard
74 private:
75 OString m_aWildString;
77 public:
78 explicit WildCard( std::u16string_view rWildCard )
79 : m_aWildString(
80 OUStringToOString(
81 rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {}
83 bool Matches( std::u16string_view rStr ) const;
88 namespace {
90 class HostnameCache
92 typedef std::pair< OUString, OUString > HostListEntry;
94 std::deque< HostListEntry > m_aHostList;
96 public:
97 bool get( std::u16string_view rKey, OUString & rValue ) const
99 for (auto const& host : m_aHostList)
101 if ( host.first == rKey )
103 rValue = host.second;
104 return true;
107 return false;
110 void put( const OUString & rKey, const OUString & rValue )
112 static constexpr sal_uInt32 nCapacity = 256;
114 if ( m_aHostList.size() == nCapacity )
115 m_aHostList.resize( nCapacity / 2 );
117 m_aHostList.push_front( HostListEntry( rKey, rValue ) );
123 class InternetProxyDecider_Impl :
124 public cppu::WeakImplHelper< util::XChangesListener >
126 // see officecfg/registry/schema/org/openoffice/Inet.xcs for the definition of these values
127 enum class ProxyType { NoProxy, Automatic, Manual };
128 mutable osl::Mutex m_aMutex;
129 InternetProxyServer m_aHttpProxy;
130 InternetProxyServer m_aHttpsProxy;
131 InternetProxyServer m_aFtpProxy;
132 const InternetProxyServer m_aEmptyProxy;
133 ProxyType m_nProxyType;
134 uno::Reference< util::XChangesNotifier > m_xNotifier;
135 typedef std::pair< WildCard, WildCard > NoProxyListEntry;
136 std::vector< NoProxyListEntry > m_aNoProxyList;
137 mutable HostnameCache m_aHostnames;
139 private:
140 bool shouldUseProxy( std::u16string_view rHost,
141 sal_Int32 nPort,
142 bool bUseFullyQualified ) const;
143 public:
144 explicit InternetProxyDecider_Impl(
145 const uno::Reference< uno::XComponentContext >& rxContext );
147 void dispose();
149 InternetProxyServer getProxy(const OUString& rProtocol,
150 const OUString & rHost,
151 sal_Int32 nPort ) const;
153 // XChangesListener
154 virtual void SAL_CALL changesOccurred( const util::ChangesEvent& Event ) override;
156 // XEventListener ( base of XChangesLisetenr )
157 virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
159 private:
160 void setNoProxyList( const OUString & rNoProxyList );
164 // WildCard Implementation.
167 bool WildCard::Matches( std::u16string_view rString ) const
169 OString aString
170 = OUStringToOString( rString, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
171 const char * pStr = aString.getStr();
172 const char * pWild = m_aWildString.getStr();
174 int pos = 0;
175 int flag = 0;
177 while ( *pWild || flag )
179 switch ( *pWild )
181 case '?':
182 if ( *pStr == '\0' )
183 return false;
184 break;
186 default:
187 if ( ( *pWild == '\\' ) && ( ( *( pWild + 1 ) == '?' )
188 || ( *( pWild + 1 ) == '*') ) )
189 pWild++;
190 if ( *pWild != *pStr )
191 if ( !pos )
192 return false;
193 else
194 pWild += pos;
195 else
196 break;
198 [[fallthrough]];
200 case '*':
201 while ( *pWild == '*' )
202 pWild++;
203 if ( *pWild == '\0' )
204 return true;
205 flag = 1;
206 pos = 0;
207 if ( *pStr == '\0' )
208 return ( *pWild == '\0' );
209 while ( *pStr && *pStr != *pWild )
211 if ( *pWild == '?' ) {
212 pWild++;
213 while ( *pWild == '*' )
214 pWild++;
216 pStr++;
217 if ( *pStr == '\0' )
218 return ( *pWild == '\0' );
220 break;
222 if ( *pWild != '\0' )
223 pWild++;
224 if ( *pStr != '\0' )
225 pStr++;
226 else
227 flag = 0;
228 if ( flag )
229 pos--;
231 return ( *pStr == '\0' ) && ( *pWild == '\0' );
235 static bool getConfigStringValue(
236 const uno::Reference< container::XNameAccess > & xNameAccess,
237 const OUString& key,
238 OUString & value )
242 if ( !( xNameAccess->getByName( key ) >>= value ) )
244 OSL_FAIL( "InternetProxyDecider - "
245 "Error getting config item value!" );
246 return false;
249 catch ( lang::WrappedTargetException const & )
251 return false;
253 catch ( container::NoSuchElementException const & )
255 return false;
257 return true;
261 static bool getConfigInt32Value(
262 const uno::Reference< container::XNameAccess > & xNameAccess,
263 const OUString& key,
264 sal_Int32 & value )
268 uno::Any aValue = xNameAccess->getByName( key );
269 if ( aValue.hasValue() && !( aValue >>= value ) )
271 OSL_FAIL( "InternetProxyDecider - "
272 "Error getting config item value!" );
273 return false;
276 catch ( lang::WrappedTargetException const & )
278 return false;
280 catch ( container::NoSuchElementException const & )
282 return false;
284 return true;
288 // InternetProxyDecider_Impl Implementation.
291 InternetProxyDecider_Impl::InternetProxyDecider_Impl(
292 const uno::Reference< uno::XComponentContext >& rxContext )
293 : m_nProxyType( ProxyType::NoProxy ),
294 m_aHostnames()
299 // Read proxy configuration from config db.
302 uno::Reference< lang::XMultiServiceFactory > xConfigProv =
303 configuration::theDefaultProvider::get( rxContext );
305 uno::Sequence< uno::Any > aArguments{ uno::Any(OUString( CONFIG_ROOT_KEY )) };
306 uno::Reference< uno::XInterface > xInterface(
307 xConfigProv->createInstanceWithArguments(
308 "com.sun.star.configuration.ConfigurationAccess",
309 aArguments ) );
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() )
323 // *** Proxy type ***
324 sal_Int32 tmp = 0;
325 getConfigInt32Value(
326 xNameAccess, PROXY_TYPE_KEY, tmp );
327 m_nProxyType = static_cast<ProxyType>(tmp);
329 // *** No proxy list ***
330 OUString aNoProxyList;
331 getConfigStringValue(
332 xNameAccess, NO_PROXY_LIST_KEY, aNoProxyList );
333 setNoProxyList( aNoProxyList );
335 // *** HTTP ***
336 getConfigStringValue(
337 xNameAccess, HTTP_PROXY_NAME_KEY, m_aHttpProxy.aName );
339 m_aHttpProxy.nPort = -1;
340 getConfigInt32Value(
341 xNameAccess, HTTP_PROXY_PORT_KEY, m_aHttpProxy.nPort );
342 if ( m_aHttpProxy.nPort == -1 )
343 m_aHttpProxy.nPort = 80; // standard HTTP port.
345 // *** HTTPS ***
346 getConfigStringValue(
347 xNameAccess, HTTPS_PROXY_NAME_KEY, m_aHttpsProxy.aName );
349 m_aHttpsProxy.nPort = -1;
350 getConfigInt32Value(
351 xNameAccess, HTTPS_PROXY_PORT_KEY, m_aHttpsProxy.nPort );
352 if ( m_aHttpsProxy.nPort == -1 )
353 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
355 // *** FTP ***
356 getConfigStringValue(
357 xNameAccess, FTP_PROXY_NAME_KEY, m_aFtpProxy.aName );
359 m_aFtpProxy.nPort = -1;
360 getConfigInt32Value(
361 xNameAccess, FTP_PROXY_PORT_KEY, m_aFtpProxy.nPort );
364 // Register as listener for config changes.
366 m_xNotifier.set( xInterface, uno::UNO_QUERY );
368 OSL_ENSURE( m_xNotifier.is(),
369 "InternetProxyDecider - No notifier!" );
371 if ( m_xNotifier.is() )
372 m_xNotifier->addChangesListener( this );
375 catch ( uno::Exception const & )
377 // createInstance, createInstanceWithArguments
378 OSL_FAIL( "InternetProxyDecider - Exception!" );
382 void InternetProxyDecider_Impl::dispose()
384 uno::Reference< util::XChangesNotifier > xNotifier;
386 if ( m_xNotifier.is() )
388 osl::Guard< osl::Mutex > aGuard( m_aMutex );
390 if ( m_xNotifier.is() )
392 xNotifier = m_xNotifier;
393 m_xNotifier.clear();
397 // Do this unguarded!
398 if ( xNotifier.is() )
399 xNotifier->removeChangesListener( this );
403 bool InternetProxyDecider_Impl::shouldUseProxy( std::u16string_view rHost,
404 sal_Int32 nPort,
405 bool bUseFullyQualified ) const
407 OUStringBuffer aBuffer;
409 if ( ( rHost.find( ':' ) != std::u16string_view::npos ) &&
410 ( rHost[ 0 ] != '[' ) )
412 // host is given as numeric IPv6 address
413 aBuffer.append( "[" );
414 aBuffer.append( rHost );
415 aBuffer.append( "]" );
417 else
419 // host is given either as numeric IPv4 address or non-numeric hostname
420 aBuffer.append( rHost );
423 aBuffer.append( ':' );
424 aBuffer.append( nPort );
425 const OUString aHostAndPort( aBuffer.makeStringAndClear() );
427 for (auto const& noProxy : m_aNoProxyList)
429 if ( bUseFullyQualified )
431 if ( noProxy.second.Matches( aHostAndPort ) )
432 return false;
434 else
436 if ( noProxy.first.Matches( aHostAndPort ) )
437 return false;
441 return true;
444 namespace
446 #ifdef _WIN32
447 struct GetPACProxyData
449 const OUString& m_rProtocol;
450 const OUString& m_rHost;
451 sal_Int32 m_nPort;
452 bool m_bAutoDetect = false;
453 OUString m_sAutoConfigUrl;
454 InternetProxyServer m_ProxyServer;
456 GetPACProxyData(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
457 : m_rProtocol(rProtocol)
458 , m_rHost(rHost)
459 , m_nPort(nPort)
464 // Tries to get proxy configuration using WinHttpGetProxyForUrl, which supports Web Proxy Auto-Discovery
465 // (WPAD) protocol and manually configured address to get Proxy Auto-Configuration (PAC) file.
466 // The WinINet/WinHTTP functions cannot correctly run in a STA COM thread, so use a dedicated thread
467 DWORD WINAPI GetPACProxyThread(_In_ LPVOID lpParameter)
469 assert(lpParameter);
470 GetPACProxyData* pData = static_cast<GetPACProxyData*>(lpParameter);
472 OUString url(pData->m_rProtocol + "://" + pData->m_rHost + ":"
473 + OUString::number(pData->m_nPort));
475 HINTERNET hInternet = WinHttpOpen(L"Mozilla 5.0", WINHTTP_ACCESS_TYPE_NO_PROXY,
476 WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
477 DWORD nError = GetLastError();
478 if (!hInternet)
479 return nError;
481 WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions{};
482 if (pData->m_bAutoDetect)
484 AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
485 AutoProxyOptions.dwAutoDetectFlags
486 = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
488 if (!pData->m_sAutoConfigUrl.isEmpty())
490 AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
491 AutoProxyOptions.lpszAutoConfigUrl = o3tl::toW(pData->m_sAutoConfigUrl.getStr());
493 // First, try without autologon. According to
494 // https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/web/winhttp/WinhttpProxySample/GetProxy.cpp
495 // autologon prevents caching, and so causes repetitive network traffic.
496 AutoProxyOptions.fAutoLogonIfChallenged = FALSE;
497 WINHTTP_PROXY_INFO ProxyInfo{};
498 bool bResult
499 = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()), &AutoProxyOptions, &ProxyInfo);
500 nError = GetLastError();
501 if (!bResult && nError == ERROR_WINHTTP_LOGIN_FAILURE)
503 AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
504 bResult = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()),
505 &AutoProxyOptions, &ProxyInfo);
506 nError = GetLastError();
508 WinHttpCloseHandle(hInternet);
509 if (bResult)
511 if (ProxyInfo.lpszProxyBypass)
512 GlobalFree(ProxyInfo.lpszProxyBypass);
513 if (ProxyInfo.lpszProxy)
515 OUString sProxyResult(o3tl::toU(ProxyInfo.lpszProxy));
516 GlobalFree(ProxyInfo.lpszProxy);
517 // Get the first of possibly multiple results
518 sProxyResult = sProxyResult.getToken(0, ';');
519 sal_Int32 nPortSepPos = sProxyResult.indexOf(':');
520 if (nPortSepPos != -1)
522 pData->m_ProxyServer.nPort = o3tl::toInt32(sProxyResult.subView(nPortSepPos + 1));
523 sProxyResult = sProxyResult.copy(0, nPortSepPos);
525 else
527 pData->m_ProxyServer.nPort = 0;
529 pData->m_ProxyServer.aName = sProxyResult;
533 return nError;
536 InternetProxyServer GetPACProxy(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
538 GetPACProxyData aData(rProtocol, rHost, nPort);
540 // WinHTTP only supports http(s), so don't try for other protocols
541 if (!(rProtocol.equalsIgnoreAsciiCase("http") || rProtocol.equalsIgnoreAsciiCase("https")))
542 return aData.m_ProxyServer;
544 // Only try to get configuration from PAC (with all the overhead, including new thread)
545 // if configured to do so
547 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG aProxyConfig{};
548 bool bResult = WinHttpGetIEProxyConfigForCurrentUser(&aProxyConfig);
549 if (aProxyConfig.lpszProxy)
550 GlobalFree(aProxyConfig.lpszProxy);
551 if (aProxyConfig.lpszProxyBypass)
552 GlobalFree(aProxyConfig.lpszProxyBypass);
553 // Don't try WPAD if AutoDetection or AutoConfig script URL are not configured
554 if (!bResult || !(aProxyConfig.fAutoDetect || aProxyConfig.lpszAutoConfigUrl))
555 return aData.m_ProxyServer;
556 aData.m_bAutoDetect = aProxyConfig.fAutoDetect;
557 if (aProxyConfig.lpszAutoConfigUrl)
559 aData.m_sAutoConfigUrl = o3tl::toU(aProxyConfig.lpszAutoConfigUrl);
560 GlobalFree(aProxyConfig.lpszAutoConfigUrl);
564 HANDLE hThread = CreateThread(nullptr, 0, GetPACProxyThread, &aData, 0, nullptr);
565 if (hThread)
567 WaitForSingleObject(hThread, INFINITE);
568 CloseHandle(hThread);
570 return aData.m_ProxyServer;
573 #else // .. _WIN32
575 // Read the settings from the OS which are stored in env vars
577 InternetProxyServer GetUnixSystemProxy(const OUString & rProtocol)
579 // TODO this could be improved to read the "no_proxy" env variable
580 InternetProxyServer aProxy;
581 OUString protocolLower = rProtocol.toAsciiLowerCase() + "_proxy";
582 OString protocolLowerStr = OUStringToOString( protocolLower, RTL_TEXTENCODING_ASCII_US );
583 const char* pEnvProxy = getenv(protocolLowerStr.getStr());
584 if (!pEnvProxy)
585 return aProxy;
586 // expecting something like "https://example.ct:80"
587 OUString tmp = OUString::createFromAscii(pEnvProxy);
588 if (tmp.getLength() < (rProtocol.getLength() + 3))
589 return aProxy;
590 tmp = tmp.copy(rProtocol.getLength() + 3);
591 sal_Int32 x = tmp.indexOf(':');
592 if (x == -1)
593 return aProxy;
594 int nPort = o3tl::toInt32(tmp.subView(x + 1));
595 if (nPort == 0)
596 return aProxy;
597 aProxy.aName = tmp.copy(0, x);
598 aProxy.nPort = nPort;
599 return aProxy;
602 #endif // else .. _WIN32
605 InternetProxyServer InternetProxyDecider_Impl::getProxy(
606 const OUString & rProtocol,
607 const OUString & rHost,
608 sal_Int32 nPort ) const
610 osl::Guard< osl::Mutex > aGuard( m_aMutex );
612 if ( m_nProxyType == ProxyType::NoProxy )
614 // Never use proxy.
615 return m_aEmptyProxy;
618 // If get from system
619 if (m_nProxyType == ProxyType::Automatic && !rHost.isEmpty())
621 #ifdef _WIN32
622 InternetProxyServer aProxy(GetPACProxy(rProtocol, rHost, nPort));
623 #else
624 InternetProxyServer aProxy(GetUnixSystemProxy(rProtocol));
625 #endif // _WIN32
626 if (!aProxy.aName.isEmpty())
627 return aProxy;
630 if ( !rHost.isEmpty() && !m_aNoProxyList.empty() )
633 // First, try direct hostname match - #110515#
636 if ( !shouldUseProxy( rHost, nPort, false ) )
637 return m_aEmptyProxy;
640 // Second, try match against full qualified hostname - #104401#
643 OUString aHost;
645 if ( ( rHost.getLength() > 1 ) &&
646 ( rHost[ 0 ] == '[' ))
648 // host is given as numeric IPv6 address. name resolution
649 // functions need hostname without square brackets.
650 aHost = rHost.copy( 1, rHost.getLength() - 2 );
652 else
654 aHost = rHost;
657 OUString aFullyQualifiedHost;
658 if ( !m_aHostnames.get( aHost, aFullyQualifiedHost ) )
660 // This might be quite expensive (DNS lookup).
661 const osl::SocketAddr aAddr( aHost, nPort );
662 aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase();
663 m_aHostnames.put( aHost, aFullyQualifiedHost );
666 // Error resolving name? -> fallback.
667 if ( aFullyQualifiedHost.isEmpty() )
668 aFullyQualifiedHost = aHost;
670 if ( aFullyQualifiedHost != aHost )
672 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, false ) )
673 return m_aEmptyProxy;
677 // Third, try match of fully qualified entries in no-proxy list
678 // against full qualified hostname
680 // Example:
681 // list: staroffice-doc -> full: xyz.germany.sun.com
682 // in: staroffice-doc.germany.sun.com -> full: xyz.germany.sun.com
685 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, true ) )
686 return m_aEmptyProxy;
689 if ( rProtocol.toAsciiLowerCase() == "ftp" )
691 if ( !m_aFtpProxy.aName.isEmpty() && m_aFtpProxy.nPort >= 0 )
692 return m_aFtpProxy;
694 else if ( rProtocol.toAsciiLowerCase() == "https" )
696 if ( !m_aHttpsProxy.aName.isEmpty() )
697 return m_aHttpsProxy;
699 else if ( !m_aHttpProxy.aName.isEmpty() )
701 // All other protocols use the HTTP proxy.
702 return m_aHttpProxy;
704 return m_aEmptyProxy;
707 // virtual
708 void SAL_CALL InternetProxyDecider_Impl::changesOccurred(
709 const util::ChangesEvent& Event )
711 osl::Guard< osl::Mutex > aGuard( m_aMutex );
713 for ( const util::ElementChange& rElem : Event.Changes )
715 OUString aKey;
716 if ( ( rElem.Accessor >>= aKey ) && !aKey.isEmpty() )
718 if ( aKey == PROXY_TYPE_KEY )
720 sal_Int32 tmp;
721 if ( !( rElem.Element >>= tmp ) )
723 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
724 "Error getting config item value!" );
726 else
727 m_nProxyType = static_cast<ProxyType>(tmp);
729 else if ( aKey == NO_PROXY_LIST_KEY )
731 OUString aNoProxyList;
732 if ( !( rElem.Element >>= aNoProxyList ) )
734 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
735 "Error getting config item value!" );
738 setNoProxyList( aNoProxyList );
740 else if ( aKey == HTTP_PROXY_NAME_KEY )
742 if ( !( rElem.Element >>= m_aHttpProxy.aName ) )
744 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
745 "Error getting config item value!" );
748 else if ( aKey == HTTP_PROXY_PORT_KEY )
750 if ( !( rElem.Element >>= m_aHttpProxy.nPort ) )
752 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
753 "Error getting config item value!" );
756 if ( m_aHttpProxy.nPort == -1 )
757 m_aHttpProxy.nPort = 80; // standard HTTP port.
759 else if ( aKey == HTTPS_PROXY_NAME_KEY )
761 if ( !( rElem.Element >>= m_aHttpsProxy.aName ) )
763 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
764 "Error getting config item value!" );
767 else if ( aKey == HTTPS_PROXY_PORT_KEY )
769 if ( !( rElem.Element >>= m_aHttpsProxy.nPort ) )
771 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
772 "Error getting config item value!" );
775 if ( m_aHttpsProxy.nPort == -1 )
776 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
778 else if ( aKey == FTP_PROXY_NAME_KEY )
780 if ( !( rElem.Element >>= m_aFtpProxy.aName ) )
782 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
783 "Error getting config item value!" );
786 else if ( aKey == FTP_PROXY_PORT_KEY )
788 if ( !( rElem.Element >>= m_aFtpProxy.nPort ) )
790 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
791 "Error getting config item value!" );
799 // virtual
800 void SAL_CALL InternetProxyDecider_Impl::disposing(const lang::EventObject&)
802 if ( m_xNotifier.is() )
804 osl::Guard< osl::Mutex > aGuard( m_aMutex );
806 if ( m_xNotifier.is() )
807 m_xNotifier.clear();
812 void InternetProxyDecider_Impl::setNoProxyList(
813 const OUString & rNoProxyList )
815 osl::Guard< osl::Mutex > aGuard( m_aMutex );
817 m_aNoProxyList.clear();
819 if ( rNoProxyList.isEmpty() )
820 return;
822 // List of connection endpoints hostname[:port],
823 // separated by semicolon. Wildcards allowed.
825 sal_Int32 nPos = 0;
826 sal_Int32 nEnd = rNoProxyList.indexOf( ';' );
827 sal_Int32 nLen = rNoProxyList.getLength();
831 if ( nEnd == -1 )
832 nEnd = nLen;
834 OUString aToken = rNoProxyList.copy( nPos, nEnd - nPos );
836 if ( !aToken.isEmpty() )
838 OUString aServer;
839 OUString aPort;
841 // numerical IPv6 address?
842 bool bIPv6Address = false;
843 sal_Int32 nClosedBracketPos = aToken.indexOf( ']' );
844 if ( nClosedBracketPos == -1 )
845 nClosedBracketPos = 0;
846 else
847 bIPv6Address = true;
849 sal_Int32 nColonPos = aToken.indexOf( ':', nClosedBracketPos );
850 if ( nColonPos == -1 )
852 // No port given, server pattern equals current token
853 aPort = "*";
854 if ( aToken.indexOf( '*' ) == -1 )
856 // pattern describes exactly one server
857 aServer = aToken;
860 aToken += ":*";
862 else
864 // Port given, extract server pattern
865 sal_Int32 nAsteriskPos = aToken.indexOf( '*' );
866 aPort = aToken.copy( nColonPos + 1 );
867 if ( nAsteriskPos < nColonPos )
869 // pattern describes exactly one server
870 aServer = aToken.copy( 0, nColonPos );
874 OUStringBuffer aFullyQualifiedHost;
875 if ( !aServer.isEmpty() )
877 // Remember fully qualified server name if current list
878 // entry specifies exactly one non-fully qualified server
879 // name.
881 // remove square brackets from host name in case it's
882 // a numerical IPv6 address.
883 if ( bIPv6Address )
884 aServer = aServer.copy( 1, aServer.getLength() - 2 );
886 // This might be quite expensive (DNS lookup).
887 const osl::SocketAddr aAddr( aServer, 0 );
888 OUString aTmp = aAddr.getHostname().toAsciiLowerCase();
889 if ( aTmp != aServer.toAsciiLowerCase() )
891 if ( bIPv6Address )
893 aFullyQualifiedHost.append( "[" );
894 aFullyQualifiedHost.append( aTmp );
895 aFullyQualifiedHost.append( "]" );
897 else
899 aFullyQualifiedHost.append( aTmp );
901 aFullyQualifiedHost.append( ":" );
902 aFullyQualifiedHost.append( aPort );
906 m_aNoProxyList.emplace_back( WildCard( aToken ),
907 WildCard( aFullyQualifiedHost ) );
910 if ( nEnd != nLen )
912 nPos = nEnd + 1;
913 nEnd = rNoProxyList.indexOf( ';', nPos );
916 while ( nEnd != nLen );
919 } // namespace proxydecider_impl
922 // InternetProxyDecider Implementation.
925 InternetProxyDecider::InternetProxyDecider(
926 const uno::Reference< uno::XComponentContext>& rxContext )
927 : m_xImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxContext ) )
932 InternetProxyDecider::~InternetProxyDecider()
934 // Break circular reference between config listener and notifier.
935 m_xImpl->dispose();
939 bool InternetProxyDecider::shouldUseProxy( const OUString & rProtocol,
940 const OUString & rHost,
941 sal_Int32 nPort ) const
943 const InternetProxyServer & rData = m_xImpl->getProxy( rProtocol,
944 rHost,
945 nPort );
946 return !rData.aName.isEmpty();
950 InternetProxyServer InternetProxyDecider::getProxy(
951 const OUString & rProtocol,
952 const OUString & rHost,
953 sal_Int32 nPort ) const
955 return m_xImpl->getProxy( rProtocol, rHost, nPort );
958 } // namespace ucbhelper
960 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */