fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / ucbhelper / source / client / proxydecider.cxx
blob5f2bf5ce057d624ca90ce8d90a0c5a81062f6d45
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 <list>
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/implbase1.hxx>
35 #include "ucbhelper/proxydecider.hxx"
37 using namespace com::sun::star;
38 using namespace ucbhelper;
40 #define CONFIG_ROOT_KEY "org.openoffice.Inet/Settings"
41 #define PROXY_TYPE_KEY "ooInetProxyType"
42 #define NO_PROXY_LIST_KEY "ooInetNoProxy"
43 #define HTTP_PROXY_NAME_KEY "ooInetHTTPProxyName"
44 #define HTTP_PROXY_PORT_KEY "ooInetHTTPProxyPort"
45 #define HTTPS_PROXY_NAME_KEY "ooInetHTTPSProxyName"
46 #define HTTPS_PROXY_PORT_KEY "ooInetHTTPSProxyPort"
47 #define FTP_PROXY_NAME_KEY "ooInetFTPProxyName"
48 #define FTP_PROXY_PORT_KEY "ooInetFTPProxyPort"
51 namespace ucbhelper
55 namespace proxydecider_impl
58 // A simple case ignoring wildcard matcher.
59 class WildCard
61 private:
62 OString m_aWildString;
64 public:
65 WildCard( const OUString& rWildCard )
66 : m_aWildString(
67 OUStringToOString(
68 rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {}
70 bool Matches( const OUString & rStr ) const;
74 typedef std::pair< WildCard, WildCard > NoProxyListEntry;
78 class HostnameCache
80 typedef std::pair< OUString, OUString > HostListEntry;
82 std::list< HostListEntry > m_aHostList;
83 sal_uInt32 m_nCapacity;
85 public:
86 explicit HostnameCache( sal_uInt32 nCapacity )
87 : m_nCapacity( nCapacity ) {}
89 bool get( const OUString & rKey, OUString & rValue ) const
91 std::list< HostListEntry >::const_iterator it
92 = m_aHostList.begin();
93 const std::list< HostListEntry >::const_iterator end
94 = m_aHostList.end();
96 while ( it != end )
98 if ( (*it).first == rKey )
100 rValue = (*it).second;
101 return true;
103 ++it;
105 return false;
108 void put( const OUString & rKey, const OUString & rValue )
110 if ( m_aHostList.size() == m_nCapacity )
111 m_aHostList.resize( m_nCapacity / 2 );
113 m_aHostList.push_front( HostListEntry( rKey, rValue ) );
118 class InternetProxyDecider_Impl :
119 public cppu::WeakImplHelper1< util::XChangesListener >
121 mutable osl::Mutex m_aMutex;
122 InternetProxyServer m_aHttpProxy;
123 InternetProxyServer m_aHttpsProxy;
124 InternetProxyServer m_aFtpProxy;
125 const InternetProxyServer m_aEmptyProxy;
126 sal_Int32 m_nProxyType;
127 uno::Reference< util::XChangesNotifier > m_xNotifier;
128 std::vector< NoProxyListEntry > m_aNoProxyList;
129 mutable HostnameCache m_aHostnames;
131 private:
132 bool shouldUseProxy( const OUString & rHost,
133 sal_Int32 nPort,
134 bool bUseFullyQualified ) const;
135 public:
136 InternetProxyDecider_Impl(
137 const uno::Reference< uno::XComponentContext >& rxContext );
138 virtual ~InternetProxyDecider_Impl();
140 void dispose();
142 const InternetProxyServer & getProxy( const OUString & rProtocol,
143 const OUString & rHost,
144 sal_Int32 nPort ) const;
146 // XChangesListener
147 virtual void SAL_CALL changesOccurred( const util::ChangesEvent& Event )
148 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
150 // XEventListener ( base of XChangesLisetenr )
151 virtual void SAL_CALL disposing( const lang::EventObject& Source )
152 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
154 private:
155 void setNoProxyList( const OUString & rNoProxyList );
161 // WildCard Implementation.
166 bool WildCard::Matches( const OUString& rString ) const
168 OString aString
169 = OUStringToOString(
170 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 // Note: fall-through are intended!
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 bool getConfigStringValue(
236 const uno::Reference< container::XNameAccess > & xNameAccess,
237 const char * key,
238 OUString & value )
242 if ( !( xNameAccess->getByName( OUString::createFromAscii( key ) )
243 >>= value ) )
245 OSL_FAIL( "InternetProxyDecider - "
246 "Error getting config item value!" );
247 return false;
250 catch ( lang::WrappedTargetException const & )
252 return false;
254 catch ( container::NoSuchElementException const & )
256 return false;
258 return true;
262 bool getConfigInt32Value(
263 const uno::Reference< container::XNameAccess > & xNameAccess,
264 const char * key,
265 sal_Int32 & value )
269 uno::Any aValue = xNameAccess->getByName(
270 OUString::createFromAscii( key ) );
271 if ( aValue.hasValue() && !( aValue >>= value ) )
273 OSL_FAIL( "InternetProxyDecider - "
274 "Error getting config item value!" );
275 return false;
278 catch ( lang::WrappedTargetException const & )
280 return false;
282 catch ( container::NoSuchElementException const & )
284 return false;
286 return true;
292 // InternetProxyDecider_Impl Implementation.
297 InternetProxyDecider_Impl::InternetProxyDecider_Impl(
298 const uno::Reference< uno::XComponentContext >& rxContext )
299 : m_nProxyType( 0 ),
300 m_aHostnames( 256 ) // cache size
305 // Read proxy configuration from config db.
308 uno::Reference< lang::XMultiServiceFactory > xConfigProv =
309 configuration::theDefaultProvider::get( rxContext );
311 uno::Sequence< uno::Any > aArguments( 1 );
312 aArguments[ 0 ] <<= OUString( CONFIG_ROOT_KEY );
314 uno::Reference< uno::XInterface > xInterface(
315 xConfigProv->createInstanceWithArguments(
316 OUString(
317 "com.sun.star.configuration.ConfigurationAccess" ),
318 aArguments ) );
320 OSL_ENSURE( xInterface.is(),
321 "InternetProxyDecider - No config access!" );
323 if ( xInterface.is() )
325 uno::Reference< container::XNameAccess > xNameAccess(
326 xInterface, uno::UNO_QUERY );
327 OSL_ENSURE( xNameAccess.is(),
328 "InternetProxyDecider - No name access!" );
330 if ( xNameAccess.is() )
332 // *** Proxy type ***
333 getConfigInt32Value(
334 xNameAccess, PROXY_TYPE_KEY, m_nProxyType );
336 // *** No proxy list ***
337 OUString aNoProxyList;
338 getConfigStringValue(
339 xNameAccess, NO_PROXY_LIST_KEY, aNoProxyList );
340 setNoProxyList( aNoProxyList );
342 // *** HTTP ***
343 getConfigStringValue(
344 xNameAccess, HTTP_PROXY_NAME_KEY, m_aHttpProxy.aName );
346 m_aHttpProxy.nPort = -1;
347 getConfigInt32Value(
348 xNameAccess, HTTP_PROXY_PORT_KEY, m_aHttpProxy.nPort );
349 if ( m_aHttpProxy.nPort == -1 )
350 m_aHttpProxy.nPort = 80; // standard HTTP port.
352 // *** HTTPS ***
353 getConfigStringValue(
354 xNameAccess, HTTPS_PROXY_NAME_KEY, m_aHttpsProxy.aName );
356 m_aHttpsProxy.nPort = -1;
357 getConfigInt32Value(
358 xNameAccess, HTTPS_PROXY_PORT_KEY, m_aHttpsProxy.nPort );
359 if ( m_aHttpsProxy.nPort == -1 )
360 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
362 // *** FTP ***
363 getConfigStringValue(
364 xNameAccess, FTP_PROXY_NAME_KEY, m_aFtpProxy.aName );
366 m_aFtpProxy.nPort = -1;
367 getConfigInt32Value(
368 xNameAccess, FTP_PROXY_PORT_KEY, m_aFtpProxy.nPort );
371 // Register as listener for config changes.
373 m_xNotifier = uno::Reference< util::XChangesNotifier >(
374 xInterface, uno::UNO_QUERY );
376 OSL_ENSURE( m_xNotifier.is(),
377 "InternetProxyDecider - No notifier!" );
379 if ( m_xNotifier.is() )
380 m_xNotifier->addChangesListener( this );
383 catch ( uno::Exception const & )
385 // createInstance, createInstanceWithArguments
386 OSL_FAIL( "InternetProxyDecider - Exception!" );
391 // virtual
392 InternetProxyDecider_Impl::~InternetProxyDecider_Impl()
397 void InternetProxyDecider_Impl::dispose()
399 uno::Reference< util::XChangesNotifier > xNotifier;
401 if ( m_xNotifier.is() )
403 osl::Guard< osl::Mutex > aGuard( m_aMutex );
405 if ( m_xNotifier.is() )
407 xNotifier = m_xNotifier;
408 m_xNotifier.clear();
412 // Do this unguarded!
413 if ( xNotifier.is() )
414 xNotifier->removeChangesListener( this );
418 bool InternetProxyDecider_Impl::shouldUseProxy( const OUString & rHost,
419 sal_Int32 nPort,
420 bool bUseFullyQualified ) const
422 OUStringBuffer aBuffer;
424 if ( ( rHost.indexOf( ':' ) != -1 ) &&
425 ( rHost[ 0 ] != '[' ) )
427 // host is given as numeric IPv6 address
428 aBuffer.appendAscii( "[" );
429 aBuffer.append( rHost );
430 aBuffer.appendAscii( "]" );
432 else
434 // host is given either as numeric IPv4 address or non-numeric hostname
435 aBuffer.append( rHost );
438 aBuffer.append( ':' );
439 aBuffer.append( OUString::number( nPort ) );
440 const OUString aHostAndPort( aBuffer.makeStringAndClear() );
442 std::vector< NoProxyListEntry >::const_iterator it
443 = m_aNoProxyList.begin();
444 const std::vector< NoProxyListEntry >::const_iterator end
445 = m_aNoProxyList.end();
447 while ( it != end )
449 if ( bUseFullyQualified )
451 if ( (*it).second.Matches( aHostAndPort ) )
452 return false;
454 else
456 if ( (*it).first.Matches( aHostAndPort ) )
457 return false;
459 ++it;
462 return true;
466 const InternetProxyServer & InternetProxyDecider_Impl::getProxy(
467 const OUString & rProtocol,
468 const OUString & rHost,
469 sal_Int32 nPort ) const
471 osl::Guard< osl::Mutex > aGuard( m_aMutex );
473 if ( m_nProxyType == 0 )
475 // Never use proxy.
476 return m_aEmptyProxy;
479 if ( !rHost.isEmpty() && !m_aNoProxyList.empty() )
482 // First, try direct hostname match - #110515#
485 if ( !shouldUseProxy( rHost, nPort, false ) )
486 return m_aEmptyProxy;
489 // Second, try match against full qualified hostname - #104401#
492 OUString aHost;
494 if ( ( rHost.getLength() > 1 ) &&
495 ( rHost[ 0 ] == '[' ))
497 // host is given as numeric IPv6 address. name resolution
498 // functions need hostname without square brackets.
499 aHost = rHost.copy( 1, rHost.getLength() - 2 );
501 else
503 aHost = rHost;
506 OUString aFullyQualifiedHost;
507 if ( !m_aHostnames.get( aHost, aFullyQualifiedHost ) )
509 // This might be quite expensive (DNS lookup).
510 const osl::SocketAddr aAddr( aHost, nPort );
511 aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase();
512 m_aHostnames.put( aHost, aFullyQualifiedHost );
515 // Error resolving name? -> fallback.
516 if ( aFullyQualifiedHost.isEmpty() )
517 aFullyQualifiedHost = aHost;
519 if ( aFullyQualifiedHost != aHost )
521 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, false ) )
522 return m_aEmptyProxy;
526 // Third, try match of fully qualified entries in no-proxy list
527 // against full qualified hostname
529 // Example:
530 // list: staroffice-doc -> full: xyz.germany.sun.com
531 // in: staroffice-doc.germany.sun.com -> full: xyz.germany.sun.com
535 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, true ) )
536 return m_aEmptyProxy;
539 if ( rProtocol.toAsciiLowerCase() == "ftp" )
541 if ( !m_aFtpProxy.aName.isEmpty() && m_aFtpProxy.nPort >= 0 )
542 return m_aFtpProxy;
544 else if ( rProtocol.toAsciiLowerCase() == "https" )
546 if ( !m_aHttpsProxy.aName.isEmpty() )
547 return m_aHttpsProxy;
549 else if ( !m_aHttpProxy.aName.isEmpty() )
551 // All other protocols use the HTTP proxy.
552 return m_aHttpProxy;
554 return m_aEmptyProxy;
558 // virtual
559 void SAL_CALL InternetProxyDecider_Impl::changesOccurred(
560 const util::ChangesEvent& Event )
561 throw( uno::RuntimeException, std::exception )
563 osl::Guard< osl::Mutex > aGuard( m_aMutex );
565 sal_Int32 nCount = Event.Changes.getLength();
566 if ( nCount )
568 const util::ElementChange* pElementChanges
569 = Event.Changes.getConstArray();
570 for ( sal_Int32 n = 0; n < nCount; ++n )
572 const util::ElementChange& rElem = pElementChanges[ n ];
573 OUString aKey;
574 if ( ( rElem.Accessor >>= aKey ) && !aKey.isEmpty() )
576 if ( aKey == PROXY_TYPE_KEY )
578 if ( !( rElem.Element >>= m_nProxyType ) )
580 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
581 "Error getting config item value!" );
584 else if ( aKey == NO_PROXY_LIST_KEY )
586 OUString aNoProxyList;
587 if ( !( rElem.Element >>= aNoProxyList ) )
589 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
590 "Error getting config item value!" );
593 setNoProxyList( aNoProxyList );
595 else if ( aKey == HTTP_PROXY_NAME_KEY )
597 if ( !( rElem.Element >>= m_aHttpProxy.aName ) )
599 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
600 "Error getting config item value!" );
603 else if ( aKey == HTTP_PROXY_PORT_KEY )
605 if ( !( rElem.Element >>= m_aHttpProxy.nPort ) )
607 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
608 "Error getting config item value!" );
611 if ( m_aHttpProxy.nPort == -1 )
612 m_aHttpProxy.nPort = 80; // standard HTTP port.
614 else if ( aKey == HTTPS_PROXY_NAME_KEY )
616 if ( !( rElem.Element >>= m_aHttpsProxy.aName ) )
618 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
619 "Error getting config item value!" );
622 else if ( aKey == HTTPS_PROXY_PORT_KEY )
624 if ( !( rElem.Element >>= m_aHttpsProxy.nPort ) )
626 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
627 "Error getting config item value!" );
630 if ( m_aHttpsProxy.nPort == -1 )
631 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
633 else if ( aKey == FTP_PROXY_NAME_KEY )
635 if ( !( rElem.Element >>= m_aFtpProxy.aName ) )
637 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
638 "Error getting config item value!" );
641 else if ( aKey == FTP_PROXY_PORT_KEY )
643 if ( !( rElem.Element >>= m_aFtpProxy.nPort ) )
645 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
646 "Error getting config item value!" );
655 // virtual
656 void SAL_CALL InternetProxyDecider_Impl::disposing(const lang::EventObject&)
657 throw( uno::RuntimeException, std::exception )
659 if ( m_xNotifier.is() )
661 osl::Guard< osl::Mutex > aGuard( m_aMutex );
663 if ( m_xNotifier.is() )
664 m_xNotifier.clear();
669 void InternetProxyDecider_Impl::setNoProxyList(
670 const OUString & rNoProxyList )
672 osl::Guard< osl::Mutex > aGuard( m_aMutex );
674 m_aNoProxyList.clear();
676 if ( !rNoProxyList.isEmpty() )
678 // List of connection endpoints hostname[:port],
679 // separated by semicolon. Wilcards allowed.
681 sal_Int32 nPos = 0;
682 sal_Int32 nEnd = rNoProxyList.indexOf( ';' );
683 sal_Int32 nLen = rNoProxyList.getLength();
687 if ( nEnd == -1 )
688 nEnd = nLen;
690 OUString aToken = rNoProxyList.copy( nPos, nEnd - nPos );
692 if ( !aToken.isEmpty() )
694 OUString aServer;
695 OUString aPort;
697 // numerical IPv6 address?
698 bool bIPv6Address = false;
699 sal_Int32 nClosedBracketPos = aToken.indexOf( ']' );
700 if ( nClosedBracketPos == -1 )
701 nClosedBracketPos = 0;
702 else
703 bIPv6Address = true;
705 sal_Int32 nColonPos = aToken.indexOf( ':', nClosedBracketPos );
706 if ( nColonPos == -1 )
708 // No port given, server pattern equals current token
709 aPort = "*";
710 if ( aToken.indexOf( '*' ) == -1 )
712 // pattern describes exactly one server
713 aServer = aToken;
716 aToken += ":*";
718 else
720 // Port given, extract server pattern
721 sal_Int32 nAsteriskPos = aToken.indexOf( '*' );
722 aPort = aToken.copy( nColonPos + 1 );
723 if ( nAsteriskPos < nColonPos )
725 // pattern describes exactly one server
726 aServer = aToken.copy( 0, nColonPos );
730 OUStringBuffer aFullyQualifiedHost;
731 if ( !aServer.isEmpty() )
733 // Remember fully qualified server name if current list
734 // entry specifies exactly one non-fully qualified server
735 // name.
737 // remove square brackets from host name in case it's
738 // a numerical IPv6 address.
739 if ( bIPv6Address )
740 aServer = aServer.copy( 1, aServer.getLength() - 2 );
742 // This might be quite expensive (DNS lookup).
743 const osl::SocketAddr aAddr( aServer, 0 );
744 OUString aTmp = aAddr.getHostname().toAsciiLowerCase();
745 if ( aTmp != aServer.toAsciiLowerCase() )
747 if ( bIPv6Address )
749 aFullyQualifiedHost.appendAscii( "[" );
750 aFullyQualifiedHost.append( aTmp );
751 aFullyQualifiedHost.appendAscii( "]" );
753 else
755 aFullyQualifiedHost.append( aTmp );
757 aFullyQualifiedHost.appendAscii( ":" );
758 aFullyQualifiedHost.append( aPort );
762 m_aNoProxyList.push_back(
763 NoProxyListEntry( WildCard( aToken ),
764 WildCard(
765 aFullyQualifiedHost
766 .makeStringAndClear() ) ) );
769 if ( nEnd != nLen )
771 nPos = nEnd + 1;
772 nEnd = rNoProxyList.indexOf( ';', nPos );
775 while ( nEnd != nLen );
779 } // namespace proxydecider_impl
784 // InternetProxyDecider Implementation.
789 InternetProxyDecider::InternetProxyDecider(
790 const uno::Reference< uno::XComponentContext>& rxContext )
791 : m_pImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxContext ) )
793 m_pImpl->acquire();
797 InternetProxyDecider::~InternetProxyDecider()
799 // Break circular reference between config listener and notifier.
800 m_pImpl->dispose();
802 // Let him go...
803 m_pImpl->release();
807 bool InternetProxyDecider::shouldUseProxy( const OUString & rProtocol,
808 const OUString & rHost,
809 sal_Int32 nPort ) const
811 const InternetProxyServer & rData = m_pImpl->getProxy( rProtocol,
812 rHost,
813 nPort );
814 return !rData.aName.isEmpty();
818 const InternetProxyServer & InternetProxyDecider::getProxy(
819 const OUString & rProtocol,
820 const OUString & rHost,
821 sal_Int32 nPort ) const
823 return m_pImpl->getProxy( rProtocol, rHost, nPort );
826 } // namespace ucbhelper
828 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */