lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / ucbhelper / source / client / proxydecider.cxx
blob31e26055ffcfcc0c8d30e2f0cd5f19e2edd3b9ff
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 <utility>
21 #include <vector>
22 #include <deque>
24 #include <osl/diagnose.h>
25 #include <osl/mutex.hxx>
26 #include <rtl/ref.hxx>
27 #include <osl/socket.hxx>
28 #include <rtl/ustrbuf.hxx>
29 #include <com/sun/star/container/XNameAccess.hpp>
30 #include <com/sun/star/configuration/theDefaultProvider.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/util/XChangesListener.hpp>
33 #include <com/sun/star/util/XChangesNotifier.hpp>
34 #include <cppuhelper/implbase.hxx>
35 #include <ucbhelper/proxydecider.hxx>
37 #ifdef _WIN32
38 #include <o3tl/char16_t2wchar_t.hxx>
39 #define WIN32_LEAN_AND_MEAN
40 #include <Windows.h>
41 #include <Winhttp.h>
42 #endif
44 using namespace com::sun::star;
45 using namespace ucbhelper;
47 #define CONFIG_ROOT_KEY "org.openoffice.Inet/Settings"
48 #define PROXY_TYPE_KEY "ooInetProxyType"
49 #define NO_PROXY_LIST_KEY "ooInetNoProxy"
50 #define HTTP_PROXY_NAME_KEY "ooInetHTTPProxyName"
51 #define HTTP_PROXY_PORT_KEY "ooInetHTTPProxyPort"
52 #define HTTPS_PROXY_NAME_KEY "ooInetHTTPSProxyName"
53 #define HTTPS_PROXY_PORT_KEY "ooInetHTTPSProxyPort"
54 #define FTP_PROXY_NAME_KEY "ooInetFTPProxyName"
55 #define FTP_PROXY_PORT_KEY "ooInetFTPProxyPort"
58 namespace ucbhelper
62 namespace proxydecider_impl
65 // A simple case ignoring wildcard matcher.
66 class WildCard
68 private:
69 OString const m_aWildString;
71 public:
72 explicit WildCard( const OUString& rWildCard )
73 : m_aWildString(
74 OUStringToOString(
75 rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {}
77 bool Matches( const OUString & rStr ) const;
81 typedef std::pair< WildCard, WildCard > NoProxyListEntry;
83 class HostnameCache
85 typedef std::pair< OUString, OUString > HostListEntry;
87 std::deque< HostListEntry > m_aHostList;
89 public:
90 bool get( const OUString & rKey, OUString & rValue ) const
92 for (auto const& host : m_aHostList)
94 if ( host.first == rKey )
96 rValue = host.second;
97 return true;
100 return false;
103 void put( const OUString & rKey, const OUString & rValue )
105 static constexpr sal_uInt32 nCapacity = 256;
107 if ( m_aHostList.size() == nCapacity )
108 m_aHostList.resize( nCapacity / 2 );
110 m_aHostList.push_front( HostListEntry( rKey, rValue ) );
115 class InternetProxyDecider_Impl :
116 public cppu::WeakImplHelper< util::XChangesListener >
118 // see officecfg/registry/schema/org/openoffice/Inet.xcs for the definition of these values
119 enum class ProxyType { NoProxy, Automatic, Manual };
120 mutable osl::Mutex m_aMutex;
121 InternetProxyServer m_aHttpProxy;
122 InternetProxyServer m_aHttpsProxy;
123 InternetProxyServer m_aFtpProxy;
124 const InternetProxyServer m_aEmptyProxy;
125 ProxyType m_nProxyType;
126 uno::Reference< util::XChangesNotifier > m_xNotifier;
127 std::vector< NoProxyListEntry > m_aNoProxyList;
128 mutable HostnameCache m_aHostnames;
130 private:
131 bool shouldUseProxy( const OUString & rHost,
132 sal_Int32 nPort,
133 bool bUseFullyQualified ) const;
134 public:
135 explicit InternetProxyDecider_Impl(
136 const uno::Reference< uno::XComponentContext >& rxContext );
138 void dispose();
140 InternetProxyServer getProxy(const OUString& rProtocol,
141 const OUString & rHost,
142 sal_Int32 nPort ) const;
144 // XChangesListener
145 virtual void SAL_CALL changesOccurred( const util::ChangesEvent& Event ) override;
147 // XEventListener ( base of XChangesLisetenr )
148 virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
150 private:
151 void setNoProxyList( const OUString & rNoProxyList );
155 // WildCard Implementation.
158 bool WildCard::Matches( const OUString& rString ) const
160 OString aString
161 = OUStringToOString( rString, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
162 const char * pStr = aString.getStr();
163 const char * pWild = m_aWildString.getStr();
165 int pos = 0;
166 int flag = 0;
168 while ( *pWild || flag )
170 switch ( *pWild )
172 case '?':
173 if ( *pStr == '\0' )
174 return false;
175 break;
177 default:
178 if ( ( *pWild == '\\' ) && ( ( *( pWild + 1 ) == '?' )
179 || ( *( pWild + 1 ) == '*') ) )
180 pWild++;
181 if ( *pWild != *pStr )
182 if ( !pos )
183 return false;
184 else
185 pWild += pos;
186 else
187 break;
189 SAL_FALLTHROUGH;
191 case '*':
192 while ( *pWild == '*' )
193 pWild++;
194 if ( *pWild == '\0' )
195 return true;
196 flag = 1;
197 pos = 0;
198 if ( *pStr == '\0' )
199 return ( *pWild == '\0' );
200 while ( *pStr && *pStr != *pWild )
202 if ( *pWild == '?' ) {
203 pWild++;
204 while ( *pWild == '*' )
205 pWild++;
207 pStr++;
208 if ( *pStr == '\0' )
209 return ( *pWild == '\0' );
211 break;
213 if ( *pWild != '\0' )
214 pWild++;
215 if ( *pStr != '\0' )
216 pStr++;
217 else
218 flag = 0;
219 if ( flag )
220 pos--;
222 return ( *pStr == '\0' ) && ( *pWild == '\0' );
226 static bool getConfigStringValue(
227 const uno::Reference< container::XNameAccess > & xNameAccess,
228 const char * key,
229 OUString & value )
233 if ( !( xNameAccess->getByName( OUString::createFromAscii( key ) )
234 >>= value ) )
236 OSL_FAIL( "InternetProxyDecider - "
237 "Error getting config item value!" );
238 return false;
241 catch ( lang::WrappedTargetException const & )
243 return false;
245 catch ( container::NoSuchElementException const & )
247 return false;
249 return true;
253 static bool getConfigInt32Value(
254 const uno::Reference< container::XNameAccess > & xNameAccess,
255 const char * key,
256 sal_Int32 & value )
260 uno::Any aValue = xNameAccess->getByName(
261 OUString::createFromAscii( key ) );
262 if ( aValue.hasValue() && !( aValue >>= value ) )
264 OSL_FAIL( "InternetProxyDecider - "
265 "Error getting config item value!" );
266 return false;
269 catch ( lang::WrappedTargetException const & )
271 return false;
273 catch ( container::NoSuchElementException const & )
275 return false;
277 return true;
281 // InternetProxyDecider_Impl Implementation.
284 InternetProxyDecider_Impl::InternetProxyDecider_Impl(
285 const uno::Reference< uno::XComponentContext >& rxContext )
286 : m_nProxyType( ProxyType::NoProxy ),
287 m_aHostnames()
292 // Read proxy configuration from config db.
295 uno::Reference< lang::XMultiServiceFactory > xConfigProv =
296 configuration::theDefaultProvider::get( rxContext );
298 uno::Sequence< uno::Any > aArguments( 1 );
299 aArguments[ 0 ] <<= OUString( CONFIG_ROOT_KEY );
301 uno::Reference< uno::XInterface > xInterface(
302 xConfigProv->createInstanceWithArguments(
303 "com.sun.star.configuration.ConfigurationAccess",
304 aArguments ) );
306 OSL_ENSURE( xInterface.is(),
307 "InternetProxyDecider - No config access!" );
309 if ( xInterface.is() )
311 uno::Reference< container::XNameAccess > xNameAccess(
312 xInterface, uno::UNO_QUERY );
313 OSL_ENSURE( xNameAccess.is(),
314 "InternetProxyDecider - No name access!" );
316 if ( xNameAccess.is() )
318 // *** Proxy type ***
319 sal_Int32 tmp = 0;
320 getConfigInt32Value(
321 xNameAccess, PROXY_TYPE_KEY, tmp );
322 m_nProxyType = static_cast<ProxyType>(tmp);
324 // *** No proxy list ***
325 OUString aNoProxyList;
326 getConfigStringValue(
327 xNameAccess, NO_PROXY_LIST_KEY, aNoProxyList );
328 setNoProxyList( aNoProxyList );
330 // *** HTTP ***
331 getConfigStringValue(
332 xNameAccess, HTTP_PROXY_NAME_KEY, m_aHttpProxy.aName );
334 m_aHttpProxy.nPort = -1;
335 getConfigInt32Value(
336 xNameAccess, HTTP_PROXY_PORT_KEY, m_aHttpProxy.nPort );
337 if ( m_aHttpProxy.nPort == -1 )
338 m_aHttpProxy.nPort = 80; // standard HTTP port.
340 // *** HTTPS ***
341 getConfigStringValue(
342 xNameAccess, HTTPS_PROXY_NAME_KEY, m_aHttpsProxy.aName );
344 m_aHttpsProxy.nPort = -1;
345 getConfigInt32Value(
346 xNameAccess, HTTPS_PROXY_PORT_KEY, m_aHttpsProxy.nPort );
347 if ( m_aHttpsProxy.nPort == -1 )
348 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
350 // *** FTP ***
351 getConfigStringValue(
352 xNameAccess, FTP_PROXY_NAME_KEY, m_aFtpProxy.aName );
354 m_aFtpProxy.nPort = -1;
355 getConfigInt32Value(
356 xNameAccess, FTP_PROXY_PORT_KEY, m_aFtpProxy.nPort );
359 // Register as listener for config changes.
361 m_xNotifier.set( xInterface, uno::UNO_QUERY );
363 OSL_ENSURE( m_xNotifier.is(),
364 "InternetProxyDecider - No notifier!" );
366 if ( m_xNotifier.is() )
367 m_xNotifier->addChangesListener( this );
370 catch ( uno::Exception const & )
372 // createInstance, createInstanceWithArguments
373 OSL_FAIL( "InternetProxyDecider - Exception!" );
377 void InternetProxyDecider_Impl::dispose()
379 uno::Reference< util::XChangesNotifier > xNotifier;
381 if ( m_xNotifier.is() )
383 osl::Guard< osl::Mutex > aGuard( m_aMutex );
385 if ( m_xNotifier.is() )
387 xNotifier = m_xNotifier;
388 m_xNotifier.clear();
392 // Do this unguarded!
393 if ( xNotifier.is() )
394 xNotifier->removeChangesListener( this );
398 bool InternetProxyDecider_Impl::shouldUseProxy( const OUString & rHost,
399 sal_Int32 nPort,
400 bool bUseFullyQualified ) const
402 OUStringBuffer aBuffer;
404 if ( ( rHost.indexOf( ':' ) != -1 ) &&
405 ( rHost[ 0 ] != '[' ) )
407 // host is given as numeric IPv6 address
408 aBuffer.append( "[" );
409 aBuffer.append( rHost );
410 aBuffer.append( "]" );
412 else
414 // host is given either as numeric IPv4 address or non-numeric hostname
415 aBuffer.append( rHost );
418 aBuffer.append( ':' );
419 aBuffer.append( OUString::number( nPort ) );
420 const OUString aHostAndPort( aBuffer.makeStringAndClear() );
422 for (auto const& noProxy : m_aNoProxyList)
424 if ( bUseFullyQualified )
426 if ( noProxy.second.Matches( aHostAndPort ) )
427 return false;
429 else
431 if ( noProxy.first.Matches( aHostAndPort ) )
432 return false;
436 return true;
439 namespace
441 #ifdef _WIN32
442 struct GetPACProxyData
444 const OUString& m_rProtocol;
445 const OUString& m_rHost;
446 sal_Int32 m_nPort;
447 bool m_bAutoDetect = false;
448 OUString m_sAutoConfigUrl;
449 InternetProxyServer m_ProxyServer;
451 GetPACProxyData(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
452 : m_rProtocol(rProtocol)
453 , m_rHost(rHost)
454 , m_nPort(nPort)
459 // Tries to get proxy configuration using WinHttpGetProxyForUrl, which supports Web Proxy Auto-Discovery
460 // (WPAD) protocol and manually configured address to get Proxy Auto-Configuration (PAC) file.
461 // The WinINet/WinHTTP functions cannot correctly run in a STA COM thread, so use a dedicated thread
462 DWORD WINAPI GetPACProxyThread(_In_ LPVOID lpParameter)
464 assert(lpParameter);
465 GetPACProxyData* pData = static_cast<GetPACProxyData*>(lpParameter);
467 OUString url(pData->m_rProtocol + "://" + pData->m_rHost + ":"
468 + OUString::number(pData->m_nPort));
470 HINTERNET hInternet = WinHttpOpen(L"Mozilla 5.0", WINHTTP_ACCESS_TYPE_NO_PROXY,
471 WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
472 DWORD nError = GetLastError();
473 if (!hInternet)
474 return nError;
476 WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions{};
477 if (pData->m_bAutoDetect)
479 AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
480 AutoProxyOptions.dwAutoDetectFlags
481 = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
483 if (!pData->m_sAutoConfigUrl.isEmpty())
485 AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
486 AutoProxyOptions.lpszAutoConfigUrl = o3tl::toW(pData->m_sAutoConfigUrl.getStr());
488 // First, try without autologon. According to
489 // https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/web/winhttp/WinhttpProxySample/GetProxy.cpp
490 // autologon prevents caching, and so causes repetitive network traffic.
491 AutoProxyOptions.fAutoLogonIfChallenged = FALSE;
492 WINHTTP_PROXY_INFO ProxyInfo{};
493 BOOL bResult
494 = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()), &AutoProxyOptions, &ProxyInfo);
495 nError = GetLastError();
496 if (!bResult && nError == ERROR_WINHTTP_LOGIN_FAILURE)
498 AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
499 bResult = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()),
500 &AutoProxyOptions, &ProxyInfo);
501 nError = GetLastError();
503 WinHttpCloseHandle(hInternet);
504 if (bResult)
506 if (ProxyInfo.lpszProxyBypass)
507 GlobalFree(ProxyInfo.lpszProxyBypass);
508 if (ProxyInfo.lpszProxy)
510 OUString sProxyResult = o3tl::toU(ProxyInfo.lpszProxy);
511 GlobalFree(ProxyInfo.lpszProxy);
512 // Get the first of possibly multiple results
513 sProxyResult = sProxyResult.getToken(0, ';');
514 sal_Int32 nPortSepPos = sProxyResult.indexOf(':');
515 if (nPortSepPos != -1)
517 pData->m_ProxyServer.nPort = sProxyResult.copy(nPortSepPos + 1).toInt32();
518 sProxyResult = sProxyResult.copy(0, nPortSepPos);
520 else
522 pData->m_ProxyServer.nPort = 0;
524 pData->m_ProxyServer.aName = sProxyResult;
528 return nError;
531 InternetProxyServer GetPACProxy(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
533 GetPACProxyData aData(rProtocol, rHost, nPort);
535 // WinHTTP only supports http(s), so don't try for other protocols
536 if (!(rProtocol.equalsIgnoreAsciiCase("http") || rProtocol.equalsIgnoreAsciiCase("https")))
537 return aData.m_ProxyServer;
539 // Only try to get configuration from PAC (with all the overhead, including new thread)
540 // if configured to do so
542 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG aProxyConfig{};
543 BOOL bResult = WinHttpGetIEProxyConfigForCurrentUser(&aProxyConfig);
544 if (aProxyConfig.lpszProxy)
545 GlobalFree(aProxyConfig.lpszProxy);
546 if (aProxyConfig.lpszProxyBypass)
547 GlobalFree(aProxyConfig.lpszProxyBypass);
548 // Don't try WPAD if AutoDetection or AutoConfig script URL are not configured
549 if (!bResult || !(aProxyConfig.fAutoDetect || aProxyConfig.lpszAutoConfigUrl))
550 return aData.m_ProxyServer;
551 aData.m_bAutoDetect = aProxyConfig.fAutoDetect;
552 if (aProxyConfig.lpszAutoConfigUrl)
554 aData.m_sAutoConfigUrl = o3tl::toU(aProxyConfig.lpszAutoConfigUrl);
555 GlobalFree(aProxyConfig.lpszAutoConfigUrl);
559 HANDLE hThread = CreateThread(nullptr, 0, GetPACProxyThread, &aData, 0, nullptr);
560 if (hThread)
562 WaitForSingleObject(hThread, INFINITE);
563 CloseHandle(hThread);
565 return aData.m_ProxyServer;
568 #else // .. _WIN32
570 // Read the settings from the OS which are stored in env vars
572 InternetProxyServer GetUnixSystemProxy(const OUString & rProtocol,
573 const OUString & /*rHost*/,
574 sal_Int32 /*nPort*/)
576 // TODO this could be improved to read the "no_proxy" env variable
577 InternetProxyServer aProxy;
578 OUString protocolLower = rProtocol.toAsciiLowerCase() + "_proxy";
579 OString protocolLowerStr = OUStringToOString( protocolLower, RTL_TEXTENCODING_ASCII_US );
580 const char* pEnvProxy = getenv(protocolLowerStr.getStr());
581 if (!pEnvProxy)
582 return aProxy;
583 // expecting something like "https://example.ct:80"
584 OUString tmp = OUString::createFromAscii(pEnvProxy);
585 if (tmp.getLength() < (rProtocol.getLength() + 3))
586 return aProxy;
587 tmp = tmp.copy(rProtocol.getLength() + 3);
588 sal_Int32 x = tmp.indexOf(':');
589 if (x == -1)
590 return aProxy;
591 int nPort = tmp.copy(x + 1).toInt32();
592 if (nPort == 0)
593 return aProxy;
594 aProxy.aName = tmp.copy(0, x);
595 aProxy.nPort = nPort;
596 return aProxy;
599 #endif // else .. _WIN32
602 InternetProxyServer InternetProxyDecider_Impl::getProxy(
603 const OUString & rProtocol,
604 const OUString & rHost,
605 sal_Int32 nPort ) const
607 osl::Guard< osl::Mutex > aGuard( m_aMutex );
609 if ( m_nProxyType == ProxyType::NoProxy )
611 // Never use proxy.
612 return m_aEmptyProxy;
615 // If get from system
616 if (m_nProxyType == ProxyType::Automatic && !rHost.isEmpty())
618 #ifdef _WIN32
619 InternetProxyServer aProxy(GetPACProxy(rProtocol, rHost, nPort));
620 #else
621 InternetProxyServer aProxy(GetUnixSystemProxy(rProtocol, rHost, nPort));
622 #endif // _WIN32
623 if (!aProxy.aName.isEmpty())
624 return aProxy;
627 if ( !rHost.isEmpty() && !m_aNoProxyList.empty() )
630 // First, try direct hostname match - #110515#
633 if ( !shouldUseProxy( rHost, nPort, false ) )
634 return m_aEmptyProxy;
637 // Second, try match against full qualified hostname - #104401#
640 OUString aHost;
642 if ( ( rHost.getLength() > 1 ) &&
643 ( rHost[ 0 ] == '[' ))
645 // host is given as numeric IPv6 address. name resolution
646 // functions need hostname without square brackets.
647 aHost = rHost.copy( 1, rHost.getLength() - 2 );
649 else
651 aHost = rHost;
654 OUString aFullyQualifiedHost;
655 if ( !m_aHostnames.get( aHost, aFullyQualifiedHost ) )
657 // This might be quite expensive (DNS lookup).
658 const osl::SocketAddr aAddr( aHost, nPort );
659 aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase();
660 m_aHostnames.put( aHost, aFullyQualifiedHost );
663 // Error resolving name? -> fallback.
664 if ( aFullyQualifiedHost.isEmpty() )
665 aFullyQualifiedHost = aHost;
667 if ( aFullyQualifiedHost != aHost )
669 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, false ) )
670 return m_aEmptyProxy;
674 // Third, try match of fully qualified entries in no-proxy list
675 // against full qualified hostname
677 // Example:
678 // list: staroffice-doc -> full: xyz.germany.sun.com
679 // in: staroffice-doc.germany.sun.com -> full: xyz.germany.sun.com
682 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, true ) )
683 return m_aEmptyProxy;
686 if ( rProtocol.toAsciiLowerCase() == "ftp" )
688 if ( !m_aFtpProxy.aName.isEmpty() && m_aFtpProxy.nPort >= 0 )
689 return m_aFtpProxy;
691 else if ( rProtocol.toAsciiLowerCase() == "https" )
693 if ( !m_aHttpsProxy.aName.isEmpty() )
694 return m_aHttpsProxy;
696 else if ( !m_aHttpProxy.aName.isEmpty() )
698 // All other protocols use the HTTP proxy.
699 return m_aHttpProxy;
701 return m_aEmptyProxy;
704 // virtual
705 void SAL_CALL InternetProxyDecider_Impl::changesOccurred(
706 const util::ChangesEvent& Event )
708 osl::Guard< osl::Mutex > aGuard( m_aMutex );
710 sal_Int32 nCount = Event.Changes.getLength();
711 if ( nCount )
713 const util::ElementChange* pElementChanges
714 = Event.Changes.getConstArray();
715 for ( sal_Int32 n = 0; n < nCount; ++n )
717 const util::ElementChange& rElem = pElementChanges[ n ];
718 OUString aKey;
719 if ( ( rElem.Accessor >>= aKey ) && !aKey.isEmpty() )
721 if ( aKey == PROXY_TYPE_KEY )
723 sal_Int32 tmp;
724 if ( !( rElem.Element >>= tmp ) )
726 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
727 "Error getting config item value!" );
729 else
730 m_nProxyType = static_cast<ProxyType>(tmp);
732 else if ( aKey == NO_PROXY_LIST_KEY )
734 OUString aNoProxyList;
735 if ( !( rElem.Element >>= aNoProxyList ) )
737 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
738 "Error getting config item value!" );
741 setNoProxyList( aNoProxyList );
743 else if ( aKey == HTTP_PROXY_NAME_KEY )
745 if ( !( rElem.Element >>= m_aHttpProxy.aName ) )
747 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
748 "Error getting config item value!" );
751 else if ( aKey == HTTP_PROXY_PORT_KEY )
753 if ( !( rElem.Element >>= m_aHttpProxy.nPort ) )
755 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
756 "Error getting config item value!" );
759 if ( m_aHttpProxy.nPort == -1 )
760 m_aHttpProxy.nPort = 80; // standard HTTP port.
762 else if ( aKey == HTTPS_PROXY_NAME_KEY )
764 if ( !( rElem.Element >>= m_aHttpsProxy.aName ) )
766 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
767 "Error getting config item value!" );
770 else if ( aKey == HTTPS_PROXY_PORT_KEY )
772 if ( !( rElem.Element >>= m_aHttpsProxy.nPort ) )
774 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
775 "Error getting config item value!" );
778 if ( m_aHttpsProxy.nPort == -1 )
779 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
781 else if ( aKey == FTP_PROXY_NAME_KEY )
783 if ( !( rElem.Element >>= m_aFtpProxy.aName ) )
785 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
786 "Error getting config item value!" );
789 else if ( aKey == FTP_PROXY_PORT_KEY )
791 if ( !( rElem.Element >>= m_aFtpProxy.nPort ) )
793 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
794 "Error getting config item value!" );
803 // virtual
804 void SAL_CALL InternetProxyDecider_Impl::disposing(const lang::EventObject&)
806 if ( m_xNotifier.is() )
808 osl::Guard< osl::Mutex > aGuard( m_aMutex );
810 if ( m_xNotifier.is() )
811 m_xNotifier.clear();
816 void InternetProxyDecider_Impl::setNoProxyList(
817 const OUString & rNoProxyList )
819 osl::Guard< osl::Mutex > aGuard( m_aMutex );
821 m_aNoProxyList.clear();
823 if ( !rNoProxyList.isEmpty() )
825 // List of connection endpoints hostname[:port],
826 // separated by semicolon. Wildcards allowed.
828 sal_Int32 nPos = 0;
829 sal_Int32 nEnd = rNoProxyList.indexOf( ';' );
830 sal_Int32 nLen = rNoProxyList.getLength();
834 if ( nEnd == -1 )
835 nEnd = nLen;
837 OUString aToken = rNoProxyList.copy( nPos, nEnd - nPos );
839 if ( !aToken.isEmpty() )
841 OUString aServer;
842 OUString aPort;
844 // numerical IPv6 address?
845 bool bIPv6Address = false;
846 sal_Int32 nClosedBracketPos = aToken.indexOf( ']' );
847 if ( nClosedBracketPos == -1 )
848 nClosedBracketPos = 0;
849 else
850 bIPv6Address = true;
852 sal_Int32 nColonPos = aToken.indexOf( ':', nClosedBracketPos );
853 if ( nColonPos == -1 )
855 // No port given, server pattern equals current token
856 aPort = "*";
857 if ( aToken.indexOf( '*' ) == -1 )
859 // pattern describes exactly one server
860 aServer = aToken;
863 aToken += ":*";
865 else
867 // Port given, extract server pattern
868 sal_Int32 nAsteriskPos = aToken.indexOf( '*' );
869 aPort = aToken.copy( nColonPos + 1 );
870 if ( nAsteriskPos < nColonPos )
872 // pattern describes exactly one server
873 aServer = aToken.copy( 0, nColonPos );
877 OUStringBuffer aFullyQualifiedHost;
878 if ( !aServer.isEmpty() )
880 // Remember fully qualified server name if current list
881 // entry specifies exactly one non-fully qualified server
882 // name.
884 // remove square brackets from host name in case it's
885 // a numerical IPv6 address.
886 if ( bIPv6Address )
887 aServer = aServer.copy( 1, aServer.getLength() - 2 );
889 // This might be quite expensive (DNS lookup).
890 const osl::SocketAddr aAddr( aServer, 0 );
891 OUString aTmp = aAddr.getHostname().toAsciiLowerCase();
892 if ( aTmp != aServer.toAsciiLowerCase() )
894 if ( bIPv6Address )
896 aFullyQualifiedHost.append( "[" );
897 aFullyQualifiedHost.append( aTmp );
898 aFullyQualifiedHost.append( "]" );
900 else
902 aFullyQualifiedHost.append( aTmp );
904 aFullyQualifiedHost.append( ":" );
905 aFullyQualifiedHost.append( aPort );
909 m_aNoProxyList.emplace_back( WildCard( aToken ),
910 WildCard( aFullyQualifiedHost.makeStringAndClear() ) );
913 if ( nEnd != nLen )
915 nPos = nEnd + 1;
916 nEnd = rNoProxyList.indexOf( ';', nPos );
919 while ( nEnd != nLen );
923 } // namespace proxydecider_impl
926 // InternetProxyDecider Implementation.
929 InternetProxyDecider::InternetProxyDecider(
930 const uno::Reference< uno::XComponentContext>& rxContext )
931 : m_xImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxContext ) )
936 InternetProxyDecider::~InternetProxyDecider()
938 // Break circular reference between config listener and notifier.
939 m_xImpl->dispose();
943 bool InternetProxyDecider::shouldUseProxy( const OUString & rProtocol,
944 const OUString & rHost,
945 sal_Int32 nPort ) const
947 const InternetProxyServer & rData = m_xImpl->getProxy( rProtocol,
948 rHost,
949 nPort );
950 return !rData.aName.isEmpty();
954 InternetProxyServer InternetProxyDecider::getProxy(
955 const OUString & rProtocol,
956 const OUString & rHost,
957 sal_Int32 nPort ) const
959 return m_xImpl->getProxy( rProtocol, rHost, nPort );
962 } // namespace ucbhelper
964 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */