bump product version to 4.1.6.2
[LibreOffice.git] / ucbhelper / source / client / proxydecider.cxx
blobf449ff9b4f920700c69d46b4d61601e3b46999ac
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 .
21 /**************************************************************************
22 TODO
23 **************************************************************************
25 *************************************************************************/
27 #include <utility>
28 #include <vector>
29 #include <list>
30 #include <osl/mutex.hxx>
31 #include <rtl/ref.hxx>
32 #include <osl/socket.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <com/sun/star/container/XNameAccess.hpp>
35 #include <com/sun/star/configuration/theDefaultProvider.hpp>
36 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
37 #include <com/sun/star/util/XChangesListener.hpp>
38 #include <com/sun/star/util/XChangesNotifier.hpp>
39 #include <cppuhelper/implbase1.hxx>
40 #include "ucbhelper/proxydecider.hxx"
42 using namespace com::sun::star;
43 using namespace ucbhelper;
45 #define CONFIG_ROOT_KEY "org.openoffice.Inet/Settings"
46 #define PROXY_TYPE_KEY "ooInetProxyType"
47 #define NO_PROXY_LIST_KEY "ooInetNoProxy"
48 #define HTTP_PROXY_NAME_KEY "ooInetHTTPProxyName"
49 #define HTTP_PROXY_PORT_KEY "ooInetHTTPProxyPort"
50 #define HTTPS_PROXY_NAME_KEY "ooInetHTTPSProxyName"
51 #define HTTPS_PROXY_PORT_KEY "ooInetHTTPSProxyPort"
52 #define FTP_PROXY_NAME_KEY "ooInetFTPProxyName"
53 #define FTP_PROXY_PORT_KEY "ooInetFTPProxyPort"
55 //=========================================================================
56 namespace ucbhelper
59 //=========================================================================
60 namespace proxydecider_impl
63 // A simple case ignoring wildcard matcher.
64 class WildCard
66 private:
67 OString m_aWildString;
69 public:
70 WildCard( const OUString& rWildCard )
71 : m_aWildString(
72 OUStringToOString(
73 rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {}
75 bool Matches( const OUString & rStr ) const;
78 //=========================================================================
79 typedef std::pair< WildCard, WildCard > NoProxyListEntry;
81 //=========================================================================
83 class HostnameCache
85 typedef std::pair< OUString, OUString > HostListEntry;
87 std::list< HostListEntry > m_aHostList;
88 sal_uInt32 m_nCapacity;
90 public:
91 explicit HostnameCache( sal_uInt32 nCapacity )
92 : m_nCapacity( nCapacity ) {}
94 bool get( const OUString & rKey, OUString & rValue ) const
96 std::list< HostListEntry >::const_iterator it
97 = m_aHostList.begin();
98 const std::list< HostListEntry >::const_iterator end
99 = m_aHostList.end();
101 while ( it != end )
103 if ( (*it).first == rKey )
105 rValue = (*it).second;
106 return true;
108 ++it;
110 return false;
113 void put( const OUString & rKey, const OUString & rValue )
115 if ( m_aHostList.size() == m_nCapacity )
116 m_aHostList.resize( m_nCapacity / 2 );
118 m_aHostList.push_front( HostListEntry( rKey, rValue ) );
122 //=========================================================================
123 class InternetProxyDecider_Impl :
124 public cppu::WeakImplHelper1< util::XChangesListener >
126 mutable osl::Mutex m_aMutex;
127 InternetProxyServer m_aHttpProxy;
128 InternetProxyServer m_aHttpsProxy;
129 InternetProxyServer m_aFtpProxy;
130 const InternetProxyServer m_aEmptyProxy;
131 sal_Int32 m_nProxyType;
132 uno::Reference< util::XChangesNotifier > m_xNotifier;
133 std::vector< NoProxyListEntry > m_aNoProxyList;
134 mutable HostnameCache m_aHostnames;
136 private:
137 bool shouldUseProxy( const OUString & rHost,
138 sal_Int32 nPort,
139 bool bUseFullyQualified ) const;
140 public:
141 InternetProxyDecider_Impl(
142 const uno::Reference< uno::XComponentContext >& rxContext );
143 virtual ~InternetProxyDecider_Impl();
145 void dispose();
147 const 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 )
153 throw( uno::RuntimeException );
155 // XEventListener ( base of XChangesLisetenr )
156 virtual void SAL_CALL disposing( const lang::EventObject& Source )
157 throw( uno::RuntimeException );
159 private:
160 void setNoProxyList( const OUString & rNoProxyList );
163 //=========================================================================
164 //=========================================================================
166 // WildCard Implementation.
168 //=========================================================================
169 //=========================================================================
171 bool WildCard::Matches( const OUString& rString ) const
173 OString aString
174 = OUStringToOString(
175 rString, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
176 const char * pStr = aString.getStr();
177 const char * pWild = m_aWildString.getStr();
179 int pos = 0;
180 int flag = 0;
182 while ( *pWild || flag )
184 switch ( *pWild )
186 case '?':
187 if ( *pStr == '\0' )
188 return 0;
189 break;
191 default:
192 if ( ( *pWild == '\\' ) && ( ( *( pWild + 1 ) == '?' )
193 || ( *( pWild + 1 ) == '*') ) )
194 pWild++;
195 if ( *pWild != *pStr )
196 if ( !pos )
197 return 0;
198 else
199 pWild += pos;
200 else
201 break;
203 // Note: fall-thru's are intended!
205 case '*':
206 while ( *pWild == '*' )
207 pWild++;
208 if ( *pWild == '\0' )
209 return 1;
210 flag = 1;
211 pos = 0;
212 if ( *pStr == '\0' )
213 return ( *pWild == '\0' );
214 while ( *pStr && *pStr != *pWild )
216 if ( *pWild == '?' ) {
217 pWild++;
218 while ( *pWild == '*' )
219 pWild++;
221 pStr++;
222 if ( *pStr == '\0' )
223 return ( *pWild == '\0' );
225 break;
227 if ( *pWild != '\0' )
228 pWild++;
229 if ( *pStr != '\0' )
230 pStr++;
231 else
232 flag = 0;
233 if ( flag )
234 pos--;
236 return ( *pStr == '\0' ) && ( *pWild == '\0' );
239 //=========================================================================
240 bool getConfigStringValue(
241 const uno::Reference< container::XNameAccess > & xNameAccess,
242 const char * key,
243 OUString & value )
247 if ( !( xNameAccess->getByName( OUString::createFromAscii( key ) )
248 >>= value ) )
250 OSL_FAIL( "InternetProxyDecider - "
251 "Error getting config item value!" );
252 return false;
255 catch ( lang::WrappedTargetException const & )
257 return false;
259 catch ( container::NoSuchElementException const & )
261 return false;
263 return true;
266 //=========================================================================
267 bool getConfigInt32Value(
268 const uno::Reference< container::XNameAccess > & xNameAccess,
269 const char * key,
270 sal_Int32 & value )
274 uno::Any aValue = xNameAccess->getByName(
275 OUString::createFromAscii( key ) );
276 if ( aValue.hasValue() && !( aValue >>= value ) )
278 OSL_FAIL( "InternetProxyDecider - "
279 "Error getting config item value!" );
280 return false;
283 catch ( lang::WrappedTargetException const & )
285 return false;
287 catch ( container::NoSuchElementException const & )
289 return false;
291 return true;
294 //=========================================================================
295 //=========================================================================
297 // InternetProxyDecider_Impl Implementation.
299 //=========================================================================
300 //=========================================================================
302 InternetProxyDecider_Impl::InternetProxyDecider_Impl(
303 const uno::Reference< uno::XComponentContext >& rxContext )
304 : m_nProxyType( 0 ),
305 m_aHostnames( 256 ) // cache size
309 //////////////////////////////////////////////////////////////
310 // Read proxy configuration from config db.
311 //////////////////////////////////////////////////////////////
313 uno::Reference< lang::XMultiServiceFactory > xConfigProv =
314 configuration::theDefaultProvider::get( rxContext );
316 uno::Sequence< uno::Any > aArguments( 1 );
317 aArguments[ 0 ] <<= OUString( CONFIG_ROOT_KEY );
319 uno::Reference< uno::XInterface > xInterface(
320 xConfigProv->createInstanceWithArguments(
321 OUString(
322 "com.sun.star.configuration.ConfigurationAccess" ),
323 aArguments ) );
325 OSL_ENSURE( xInterface.is(),
326 "InternetProxyDecider - No config access!" );
328 if ( xInterface.is() )
330 uno::Reference< container::XNameAccess > xNameAccess(
331 xInterface, uno::UNO_QUERY );
332 OSL_ENSURE( xNameAccess.is(),
333 "InternetProxyDecider - No name access!" );
335 if ( xNameAccess.is() )
337 // *** Proxy type ***
338 getConfigInt32Value(
339 xNameAccess, PROXY_TYPE_KEY, m_nProxyType );
341 // *** No proxy list ***
342 OUString aNoProxyList;
343 getConfigStringValue(
344 xNameAccess, NO_PROXY_LIST_KEY, aNoProxyList );
345 setNoProxyList( aNoProxyList );
347 // *** HTTP ***
348 getConfigStringValue(
349 xNameAccess, HTTP_PROXY_NAME_KEY, m_aHttpProxy.aName );
351 m_aHttpProxy.nPort = -1;
352 getConfigInt32Value(
353 xNameAccess, HTTP_PROXY_PORT_KEY, m_aHttpProxy.nPort );
354 if ( m_aHttpProxy.nPort == -1 )
355 m_aHttpProxy.nPort = 80; // standard HTTP port.
357 // *** HTTPS ***
358 getConfigStringValue(
359 xNameAccess, HTTPS_PROXY_NAME_KEY, m_aHttpsProxy.aName );
361 m_aHttpsProxy.nPort = -1;
362 getConfigInt32Value(
363 xNameAccess, HTTPS_PROXY_PORT_KEY, m_aHttpsProxy.nPort );
364 if ( m_aHttpsProxy.nPort == -1 )
365 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
367 // *** FTP ***
368 getConfigStringValue(
369 xNameAccess, FTP_PROXY_NAME_KEY, m_aFtpProxy.aName );
371 m_aFtpProxy.nPort = -1;
372 getConfigInt32Value(
373 xNameAccess, FTP_PROXY_PORT_KEY, m_aFtpProxy.nPort );
376 // Register as listener for config changes.
378 m_xNotifier = uno::Reference< util::XChangesNotifier >(
379 xInterface, uno::UNO_QUERY );
381 OSL_ENSURE( m_xNotifier.is(),
382 "InternetProxyDecider - No notifier!" );
384 if ( m_xNotifier.is() )
385 m_xNotifier->addChangesListener( this );
388 catch ( uno::Exception const & )
390 // createInstance, createInstanceWithArguments
391 OSL_FAIL( "InternetProxyDecider - Exception!" );
395 //=========================================================================
396 // virtual
397 InternetProxyDecider_Impl::~InternetProxyDecider_Impl()
401 //=========================================================================
402 void InternetProxyDecider_Impl::dispose()
404 uno::Reference< util::XChangesNotifier > xNotifier;
406 if ( m_xNotifier.is() )
408 osl::Guard< osl::Mutex > aGuard( m_aMutex );
410 if ( m_xNotifier.is() )
412 xNotifier = m_xNotifier;
413 m_xNotifier.clear();
417 // Do this unguarded!
418 if ( xNotifier.is() )
419 xNotifier->removeChangesListener( this );
422 //=========================================================================
423 bool InternetProxyDecider_Impl::shouldUseProxy( const OUString & rHost,
424 sal_Int32 nPort,
425 bool bUseFullyQualified ) const
427 OUStringBuffer aBuffer;
429 if ( ( rHost.indexOf( ':' ) != -1 ) &&
430 ( rHost[ 0 ] != sal_Unicode( '[' ) ) )
432 // host is given as numeric IPv6 address
433 aBuffer.appendAscii( "[" );
434 aBuffer.append( rHost );
435 aBuffer.appendAscii( "]" );
437 else
439 // host is given either as numeric IPv4 address or non-numeric hostname
440 aBuffer.append( rHost );
443 aBuffer.append( sal_Unicode( ':' ) );
444 aBuffer.append( OUString::valueOf( nPort ) );
445 const OUString aHostAndPort( aBuffer.makeStringAndClear() );
447 std::vector< NoProxyListEntry >::const_iterator it
448 = m_aNoProxyList.begin();
449 const std::vector< NoProxyListEntry >::const_iterator end
450 = m_aNoProxyList.end();
452 while ( it != end )
454 if ( bUseFullyQualified )
456 if ( (*it).second.Matches( aHostAndPort ) )
457 return false;
459 else
461 if ( (*it).first.Matches( aHostAndPort ) )
462 return false;
464 ++it;
467 return true;
470 //=========================================================================
471 const InternetProxyServer & InternetProxyDecider_Impl::getProxy(
472 const OUString & rProtocol,
473 const OUString & rHost,
474 sal_Int32 nPort ) const
476 osl::Guard< osl::Mutex > aGuard( m_aMutex );
478 if ( m_nProxyType == 0 )
480 // Never use proxy.
481 return m_aEmptyProxy;
484 if ( !rHost.isEmpty() && !m_aNoProxyList.empty() )
486 //////////////////////////////////////////////////////////////////
487 // First, try direct hostname match - #110515#
488 //////////////////////////////////////////////////////////////////
490 if ( !shouldUseProxy( rHost, nPort, false ) )
491 return m_aEmptyProxy;
493 //////////////////////////////////////////////////////////////////
494 // Second, try match against full qualified hostname - #104401#
495 //////////////////////////////////////////////////////////////////
497 OUString aHost;
499 if ( ( rHost[ 0 ] == sal_Unicode( '[' ) ) &&
500 ( rHost.getLength() > 1 ) )
502 // host is given as numeric IPv6 address. name resolution
503 // functions need hostname without square brackets.
504 aHost = rHost.copy( 1, rHost.getLength() - 2 );
506 else
508 aHost = rHost;
511 OUString aFullyQualifiedHost;
512 if ( !m_aHostnames.get( aHost, aFullyQualifiedHost ) )
514 // This might be quite expensive (DNS lookup).
515 const osl::SocketAddr aAddr( aHost, nPort );
516 aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase();
517 m_aHostnames.put( aHost, aFullyQualifiedHost );
520 // Error resolving name? -> fallback.
521 if ( aFullyQualifiedHost.isEmpty() )
522 aFullyQualifiedHost = aHost;
524 if ( aFullyQualifiedHost != aHost )
526 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, false ) )
527 return m_aEmptyProxy;
530 //////////////////////////////////////////////////////////////////
531 // Third, try match of fully qualified entries in no-proxy list
532 // against full qualified hostname
534 // Example:
535 // list: staroffice-doc -> full: xyz.germany.sun.com
536 // in: staroffice-doc.germany.sun.com -> full: xyz.germany.sun.com
538 //////////////////////////////////////////////////////////////////
540 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, true ) )
541 return m_aEmptyProxy;
544 if ( rProtocol.toAsciiLowerCase() == "ftp" )
546 if ( !m_aFtpProxy.aName.isEmpty() && m_aFtpProxy.nPort >= 0 )
547 return m_aFtpProxy;
549 else if ( rProtocol.toAsciiLowerCase() == "https" )
551 if ( !m_aHttpsProxy.aName.isEmpty() )
552 return m_aHttpsProxy;
554 else if ( !m_aHttpProxy.aName.isEmpty() )
556 // All other protocols use the HTTP proxy.
557 return m_aHttpProxy;
559 return m_aEmptyProxy;
562 //=========================================================================
563 // virtual
564 void SAL_CALL InternetProxyDecider_Impl::changesOccurred(
565 const util::ChangesEvent& Event )
566 throw( uno::RuntimeException )
568 osl::Guard< osl::Mutex > aGuard( m_aMutex );
570 sal_Int32 nCount = Event.Changes.getLength();
571 if ( nCount )
573 const util::ElementChange* pElementChanges
574 = Event.Changes.getConstArray();
575 for ( sal_Int32 n = 0; n < nCount; ++n )
577 const util::ElementChange& rElem = pElementChanges[ n ];
578 OUString aKey;
579 if ( ( rElem.Accessor >>= aKey ) && !aKey.isEmpty() )
581 if ( aKey == PROXY_TYPE_KEY )
583 if ( !( rElem.Element >>= m_nProxyType ) )
585 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
586 "Error getting config item value!" );
589 else if ( aKey == NO_PROXY_LIST_KEY )
591 OUString aNoProxyList;
592 if ( !( rElem.Element >>= aNoProxyList ) )
594 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
595 "Error getting config item value!" );
598 setNoProxyList( aNoProxyList );
600 else if ( aKey == HTTP_PROXY_NAME_KEY )
602 if ( !( rElem.Element >>= m_aHttpProxy.aName ) )
604 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
605 "Error getting config item value!" );
608 else if ( aKey == HTTP_PROXY_PORT_KEY )
610 if ( !( rElem.Element >>= m_aHttpProxy.nPort ) )
612 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
613 "Error getting config item value!" );
616 if ( m_aHttpProxy.nPort == -1 )
617 m_aHttpProxy.nPort = 80; // standard HTTP port.
619 else if ( aKey == HTTPS_PROXY_NAME_KEY )
621 if ( !( rElem.Element >>= m_aHttpsProxy.aName ) )
623 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
624 "Error getting config item value!" );
627 else if ( aKey == HTTPS_PROXY_PORT_KEY )
629 if ( !( rElem.Element >>= m_aHttpsProxy.nPort ) )
631 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
632 "Error getting config item value!" );
635 if ( m_aHttpsProxy.nPort == -1 )
636 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
638 else if ( aKey == FTP_PROXY_NAME_KEY )
640 if ( !( rElem.Element >>= m_aFtpProxy.aName ) )
642 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
643 "Error getting config item value!" );
646 else if ( aKey == FTP_PROXY_PORT_KEY )
648 if ( !( rElem.Element >>= m_aFtpProxy.nPort ) )
650 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
651 "Error getting config item value!" );
659 //=========================================================================
660 // virtual
661 void SAL_CALL InternetProxyDecider_Impl::disposing(const lang::EventObject&)
662 throw( uno::RuntimeException )
664 if ( m_xNotifier.is() )
666 osl::Guard< osl::Mutex > aGuard( m_aMutex );
668 if ( m_xNotifier.is() )
669 m_xNotifier.clear();
673 //=========================================================================
674 void InternetProxyDecider_Impl::setNoProxyList(
675 const OUString & rNoProxyList )
677 osl::Guard< osl::Mutex > aGuard( m_aMutex );
679 m_aNoProxyList.clear();
681 if ( !rNoProxyList.isEmpty() )
683 // List of connection endpoints hostname[:port],
684 // separated by semicolon. Wilcards allowed.
686 sal_Int32 nPos = 0;
687 sal_Int32 nEnd = rNoProxyList.indexOf( ';' );
688 sal_Int32 nLen = rNoProxyList.getLength();
692 if ( nEnd == -1 )
693 nEnd = nLen;
695 OUString aToken = rNoProxyList.copy( nPos, nEnd - nPos );
697 if ( !aToken.isEmpty() )
699 OUString aServer;
700 OUString aPort;
702 // numerical IPv6 address?
703 bool bIPv6Address = false;
704 sal_Int32 nClosedBracketPos = aToken.indexOf( ']' );
705 if ( nClosedBracketPos == -1 )
706 nClosedBracketPos = 0;
707 else
708 bIPv6Address = true;
710 sal_Int32 nColonPos = aToken.indexOf( ':', nClosedBracketPos );
711 if ( nColonPos == -1 )
713 // No port given, server pattern equals current token
714 aPort = OUString("*");
715 if ( aToken.indexOf( '*' ) == -1 )
717 // pattern describes exactly one server
718 aServer = aToken;
721 aToken += OUString(":*");
723 else
725 // Port given, extract server pattern
726 sal_Int32 nAsterixPos = aToken.indexOf( '*' );
727 aPort = aToken.copy( nColonPos + 1 );
728 if ( nAsterixPos < nColonPos )
730 // pattern describes exactly one server
731 aServer = aToken.copy( 0, nColonPos );
735 OUStringBuffer aFullyQualifiedHost;
736 if ( !aServer.isEmpty() )
738 // Remember fully qualified server name if current list
739 // entry specifies exactly one non-fully qualified server
740 // name.
742 // remove square brackets from host name in case it's
743 // a numerical IPv6 address.
744 if ( bIPv6Address )
745 aServer = aServer.copy( 1, aServer.getLength() - 2 );
747 // This might be quite expensive (DNS lookup).
748 const osl::SocketAddr aAddr( aServer, 0 );
749 OUString aTmp = aAddr.getHostname().toAsciiLowerCase();
750 if ( aTmp != aServer.toAsciiLowerCase() )
752 if ( bIPv6Address )
754 aFullyQualifiedHost.appendAscii( "[" );
755 aFullyQualifiedHost.append( aTmp );
756 aFullyQualifiedHost.appendAscii( "]" );
758 else
760 aFullyQualifiedHost.append( aTmp );
762 aFullyQualifiedHost.appendAscii( ":" );
763 aFullyQualifiedHost.append( aPort );
767 m_aNoProxyList.push_back(
768 NoProxyListEntry( WildCard( aToken ),
769 WildCard(
770 aFullyQualifiedHost
771 .makeStringAndClear() ) ) );
774 if ( nEnd != nLen )
776 nPos = nEnd + 1;
777 nEnd = rNoProxyList.indexOf( ';', nPos );
780 while ( nEnd != nLen );
784 } // namespace proxydecider_impl
786 //=========================================================================
787 //=========================================================================
789 // InternetProxyDecider Implementation.
791 //=========================================================================
792 //=========================================================================
794 InternetProxyDecider::InternetProxyDecider(
795 const uno::Reference< uno::XComponentContext>& rxContext )
796 : m_pImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxContext ) )
798 m_pImpl->acquire();
801 //=========================================================================
802 InternetProxyDecider::~InternetProxyDecider()
804 // Break circular reference between config listener and notifier.
805 m_pImpl->dispose();
807 // Let him go...
808 m_pImpl->release();
811 //=========================================================================
812 bool InternetProxyDecider::shouldUseProxy( const OUString & rProtocol,
813 const OUString & rHost,
814 sal_Int32 nPort ) const
816 const InternetProxyServer & rData = m_pImpl->getProxy( rProtocol,
817 rHost,
818 nPort );
819 return !rData.aName.isEmpty();
822 //=========================================================================
823 const InternetProxyServer & InternetProxyDecider::getProxy(
824 const OUString & rProtocol,
825 const OUString & rHost,
826 sal_Int32 nPort ) const
828 return m_pImpl->getProxy( rProtocol, rHost, nPort );
831 } // namespace ucbhelper
833 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */