LibreOffice Module ucbhelper (master) 1
proxydecider.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <string_view>
23#include <utility>
24#include <vector>
25#include <deque>
26
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>
39#include <o3tl/string_view.hxx>
40
41#ifdef _WIN32
43#define WIN32_LEAN_AND_MEAN
44#include <Windows.h>
45#include <Winhttp.h>
46#endif
47
48using namespace com::sun::star;
49using namespace ucbhelper;
50
51constexpr OUStringLiteral CONFIG_ROOT_KEY = u"org.openoffice.Inet/Settings";
52constexpr OUStringLiteral PROXY_TYPE_KEY = u"ooInetProxyType";
53constexpr OUStringLiteral NO_PROXY_LIST_KEY = u"ooInetNoProxy";
54constexpr OUStringLiteral HTTP_PROXY_NAME_KEY = u"ooInetHTTPProxyName";
55constexpr OUStringLiteral HTTP_PROXY_PORT_KEY = u"ooInetHTTPProxyPort";
56constexpr OUStringLiteral HTTPS_PROXY_NAME_KEY = u"ooInetHTTPSProxyName";
57constexpr OUStringLiteral HTTPS_PROXY_PORT_KEY = u"ooInetHTTPSProxyPort";
58constexpr OUStringLiteral FTP_PROXY_NAME_KEY = u"ooInetFTPProxyName";
59constexpr OUStringLiteral FTP_PROXY_PORT_KEY = u"ooInetFTPProxyPort";
60
61
62namespace ucbhelper
63{
64
65
66namespace proxydecider_impl
67{
68
69namespace {
70
71// A simple case ignoring wildcard matcher.
72class WildCard
73{
74private:
76
77public:
78 explicit WildCard( std::u16string_view rWildCard )
81 rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {}
82
83 bool Matches( std::u16string_view rStr ) const;
84};
85
86}
87
88namespace {
89
90class HostnameCache
91{
92 typedef std::pair< OUString, OUString > HostListEntry;
93
94 std::deque< HostListEntry > m_aHostList;
95
96public:
97 bool get( std::u16string_view rKey, OUString & rValue ) const
98 {
99 for (auto const& host : m_aHostList)
100 {
101 if ( host.first == rKey )
102 {
103 rValue = host.second;
104 return true;
105 }
106 }
107 return false;
108 }
109
110 void put( const OUString & rKey, const OUString & rValue )
111 {
112 static constexpr sal_uInt32 nCapacity = 256;
113
114 if ( m_aHostList.size() == nCapacity )
115 m_aHostList.resize( nCapacity / 2 );
116
117 m_aHostList.push_front( HostListEntry( rKey, rValue ) );
118 }
119};
120
121}
122
124 public cppu::WeakImplHelper< util::XChangesListener >
125{
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;
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;
138
139private:
140 bool shouldUseProxy( std::u16string_view rHost,
141 sal_Int32 nPort,
142 bool bUseFullyQualified ) const;
143public:
145 const uno::Reference< uno::XComponentContext >& rxContext );
146
147 void dispose();
148
149 InternetProxyServer getProxy(const OUString& rProtocol,
150 const OUString & rHost,
151 sal_Int32 nPort ) const;
152
153 // XChangesListener
154 virtual void SAL_CALL changesOccurred( const util::ChangesEvent& Event ) override;
155
156 // XEventListener ( base of XChangesLisetenr )
157 virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
158
159private:
160 void setNoProxyList( const OUString & rNoProxyList );
161};
162
163
164// WildCard Implementation.
165
166
167bool WildCard::Matches( std::u16string_view rString ) const
168{
169 OString aString
170 = OUStringToOString( rString, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
171 const char * pStr = aString.getStr();
172 const char * pWild = m_aWildString.getStr();
173
174 int pos = 0;
175 int flag = 0;
176
177 while ( *pWild || flag )
178 {
179 switch ( *pWild )
180 {
181 case '?':
182 if ( *pStr == '\0' )
183 return false;
184 break;
185
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;
197
198 [[fallthrough]];
199
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 )
210 {
211 if ( *pWild == '?' ) {
212 pWild++;
213 while ( *pWild == '*' )
214 pWild++;
215 }
216 pStr++;
217 if ( *pStr == '\0' )
218 return ( *pWild == '\0' );
219 }
220 break;
221 }
222 if ( *pWild != '\0' )
223 pWild++;
224 if ( *pStr != '\0' )
225 pStr++;
226 else
227 flag = 0;
228 if ( flag )
229 pos--;
230 }
231 return ( *pStr == '\0' ) && ( *pWild == '\0' );
232}
233
234
236 const uno::Reference< container::XNameAccess > & xNameAccess,
237 const OUString& key,
238 OUString & value )
239{
240 try
241 {
242 if ( !( xNameAccess->getByName( key ) >>= value ) )
243 {
244 OSL_FAIL( "InternetProxyDecider - "
245 "Error getting config item value!" );
246 return false;
247 }
248 }
249 catch ( lang::WrappedTargetException const & )
250 {
251 return false;
252 }
253 catch ( container::NoSuchElementException const & )
254 {
255 return false;
256 }
257 return true;
258}
259
260
262 const uno::Reference< container::XNameAccess > & xNameAccess,
263 const OUString& key,
264 sal_Int32 & value )
265{
266 try
267 {
268 uno::Any aValue = xNameAccess->getByName( key );
269 if ( aValue.hasValue() && !( aValue >>= value ) )
270 {
271 OSL_FAIL( "InternetProxyDecider - "
272 "Error getting config item value!" );
273 return false;
274 }
275 }
276 catch ( lang::WrappedTargetException const & )
277 {
278 return false;
279 }
280 catch ( container::NoSuchElementException const & )
281 {
282 return false;
283 }
284 return true;
285}
286
287
288// InternetProxyDecider_Impl Implementation.
289
290
292 const uno::Reference< uno::XComponentContext >& rxContext )
293 : m_nProxyType( ProxyType::NoProxy ),
294 m_aHostnames()
295{
296 try
297 {
298
299 // Read proxy configuration from config db.
300
301
302 uno::Reference< lang::XMultiServiceFactory > xConfigProv =
303 configuration::theDefaultProvider::get( rxContext );
304
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 ) );
310
311 OSL_ENSURE( xInterface.is(),
312 "InternetProxyDecider - No config access!" );
313
314 if ( xInterface.is() )
315 {
316 uno::Reference< container::XNameAccess > xNameAccess(
317 xInterface, uno::UNO_QUERY );
318 OSL_ENSURE( xNameAccess.is(),
319 "InternetProxyDecider - No name access!" );
320
321 if ( xNameAccess.is() )
322 {
323 // *** Proxy type ***
324 sal_Int32 tmp = 0;
326 xNameAccess, PROXY_TYPE_KEY, tmp );
327 m_nProxyType = static_cast<ProxyType>(tmp);
328
329 // *** No proxy list ***
330 OUString aNoProxyList;
332 xNameAccess, NO_PROXY_LIST_KEY, aNoProxyList );
333 setNoProxyList( aNoProxyList );
334
335 // *** HTTP ***
337 xNameAccess, HTTP_PROXY_NAME_KEY, m_aHttpProxy.aName );
338
339 m_aHttpProxy.nPort = -1;
341 xNameAccess, HTTP_PROXY_PORT_KEY, m_aHttpProxy.nPort );
342 if ( m_aHttpProxy.nPort == -1 )
343 m_aHttpProxy.nPort = 80; // standard HTTP port.
344
345 // *** HTTPS ***
348
349 m_aHttpsProxy.nPort = -1;
352 if ( m_aHttpsProxy.nPort == -1 )
353 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
354
355 // *** FTP ***
357 xNameAccess, FTP_PROXY_NAME_KEY, m_aFtpProxy.aName );
358
359 m_aFtpProxy.nPort = -1;
361 xNameAccess, FTP_PROXY_PORT_KEY, m_aFtpProxy.nPort );
362 }
363
364 // Register as listener for config changes.
365
366 m_xNotifier.set( xInterface, uno::UNO_QUERY );
367
368 OSL_ENSURE( m_xNotifier.is(),
369 "InternetProxyDecider - No notifier!" );
370
371 if ( m_xNotifier.is() )
372 m_xNotifier->addChangesListener( this );
373 }
374 }
375 catch ( uno::Exception const & )
376 {
377 // createInstance, createInstanceWithArguments
378 OSL_FAIL( "InternetProxyDecider - Exception!" );
379 }
380}
381
383{
384 uno::Reference< util::XChangesNotifier > xNotifier;
385
386 if ( m_xNotifier.is() )
387 {
388 osl::Guard< osl::Mutex > aGuard( m_aMutex );
389
390 if ( m_xNotifier.is() )
391 {
392 xNotifier = m_xNotifier;
393 m_xNotifier.clear();
394 }
395 }
396
397 // Do this unguarded!
398 if ( xNotifier.is() )
399 xNotifier->removeChangesListener( this );
400}
401
402
403bool InternetProxyDecider_Impl::shouldUseProxy( std::u16string_view rHost,
404 sal_Int32 nPort,
405 bool bUseFullyQualified ) const
406{
407 OUStringBuffer aBuffer;
408
409 if ( ( rHost.find( ':' ) != std::u16string_view::npos ) &&
410 ( rHost[ 0 ] != '[' ) )
411 {
412 // host is given as numeric IPv6 address
413 aBuffer.append( OUString::Concat("[") + rHost + "]" );
414 }
415 else
416 {
417 // host is given either as numeric IPv4 address or non-numeric hostname
418 aBuffer.append( rHost );
419 }
420
421 aBuffer.append( ":" + OUString::number( nPort ) );
422
423 for (auto const& noProxy : m_aNoProxyList)
424 {
425 if ( bUseFullyQualified )
426 {
427 if ( noProxy.second.Matches( aBuffer ) )
428 return false;
429 }
430 else
431 {
432 if ( noProxy.first.Matches( aBuffer ) )
433 return false;
434 }
435 }
436
437 return true;
438}
439
440namespace
441{
442#ifdef _WIN32
443struct GetPACProxyData
444{
445 const OUString& m_rProtocol;
446 const OUString& m_rHost;
447 sal_Int32 m_nPort;
448 bool m_bAutoDetect = false;
449 OUString m_sAutoConfigUrl;
450 InternetProxyServer m_ProxyServer;
451
452 GetPACProxyData(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
453 : m_rProtocol(rProtocol)
454 , m_rHost(rHost)
455 , m_nPort(nPort)
456 {
457 }
458};
459
460// Tries to get proxy configuration using WinHttpGetProxyForUrl, which supports Web Proxy Auto-Discovery
461// (WPAD) protocol and manually configured address to get Proxy Auto-Configuration (PAC) file.
462// The WinINet/WinHTTP functions cannot correctly run in a STA COM thread, so use a dedicated thread
463DWORD WINAPI GetPACProxyThread(_In_ LPVOID lpParameter)
464{
465 assert(lpParameter);
466 GetPACProxyData* pData = static_cast<GetPACProxyData*>(lpParameter);
467
468 OUString url(pData->m_rProtocol + "://" + pData->m_rHost + ":"
469 + OUString::number(pData->m_nPort));
470
471 HINTERNET hInternet = WinHttpOpen(L"Mozilla 5.0", WINHTTP_ACCESS_TYPE_NO_PROXY,
472 WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
473 DWORD nError = GetLastError();
474 if (!hInternet)
475 return nError;
476
477 WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions{};
478 if (pData->m_bAutoDetect)
479 {
480 AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
481 AutoProxyOptions.dwAutoDetectFlags
482 = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
483 }
484 if (!pData->m_sAutoConfigUrl.isEmpty())
485 {
486 AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
487 AutoProxyOptions.lpszAutoConfigUrl = o3tl::toW(pData->m_sAutoConfigUrl.getStr());
488 }
489 // First, try without autologon. According to
490 // https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/web/winhttp/WinhttpProxySample/GetProxy.cpp
491 // autologon prevents caching, and so causes repetitive network traffic.
492 AutoProxyOptions.fAutoLogonIfChallenged = FALSE;
493 WINHTTP_PROXY_INFO ProxyInfo{};
494 bool bResult
495 = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()), &AutoProxyOptions, &ProxyInfo);
496 nError = GetLastError();
497 if (!bResult && nError == ERROR_WINHTTP_LOGIN_FAILURE)
498 {
499 AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
500 bResult = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()),
501 &AutoProxyOptions, &ProxyInfo);
502 nError = GetLastError();
503 }
504 WinHttpCloseHandle(hInternet);
505 if (bResult)
506 {
507 if (ProxyInfo.lpszProxyBypass)
508 GlobalFree(ProxyInfo.lpszProxyBypass);
509 if (ProxyInfo.lpszProxy)
510 {
511 OUString sProxyResult(o3tl::toU(ProxyInfo.lpszProxy));
512 GlobalFree(ProxyInfo.lpszProxy);
513 // Get the first of possibly multiple results
514 sProxyResult = sProxyResult.getToken(0, ';');
515 sal_Int32 nPortSepPos = sProxyResult.indexOf(':');
516 if (nPortSepPos != -1)
517 {
518 pData->m_ProxyServer.nPort = o3tl::toInt32(sProxyResult.subView(nPortSepPos + 1));
519 sProxyResult = sProxyResult.copy(0, nPortSepPos);
520 }
521 else
522 {
523 pData->m_ProxyServer.nPort = 0;
524 }
525 pData->m_ProxyServer.aName = sProxyResult;
526 }
527 }
528
529 return nError;
530}
531
532InternetProxyServer GetPACProxy(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
533{
534 GetPACProxyData aData(rProtocol, rHost, nPort);
535
536 // WinHTTP only supports http(s), so don't try for other protocols
537 if (!(rProtocol.equalsIgnoreAsciiCase("http") || rProtocol.equalsIgnoreAsciiCase("https")))
538 return aData.m_ProxyServer;
539
540 // Only try to get configuration from PAC (with all the overhead, including new thread)
541 // if configured to do so
542 {
543 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG aProxyConfig{};
544 bool bResult = WinHttpGetIEProxyConfigForCurrentUser(&aProxyConfig);
545 if (aProxyConfig.lpszProxy)
546 GlobalFree(aProxyConfig.lpszProxy);
547 if (aProxyConfig.lpszProxyBypass)
548 GlobalFree(aProxyConfig.lpszProxyBypass);
549 // Don't try WPAD if AutoDetection or AutoConfig script URL are not configured
550 if (!bResult || !(aProxyConfig.fAutoDetect || aProxyConfig.lpszAutoConfigUrl))
551 return aData.m_ProxyServer;
552 aData.m_bAutoDetect = aProxyConfig.fAutoDetect;
553 if (aProxyConfig.lpszAutoConfigUrl)
554 {
555 aData.m_sAutoConfigUrl = o3tl::toU(aProxyConfig.lpszAutoConfigUrl);
556 GlobalFree(aProxyConfig.lpszAutoConfigUrl);
557 }
558 }
559
560 HANDLE hThread = CreateThread(nullptr, 0, GetPACProxyThread, &aData, 0, nullptr);
561 if (hThread)
562 {
563 WaitForSingleObject(hThread, INFINITE);
564 CloseHandle(hThread);
565 }
566 return aData.m_ProxyServer;
567}
568
569#else // .. _WIN32
570
571// Read the settings from the OS which are stored in env vars
572//
573InternetProxyServer GetUnixSystemProxy(const OUString & rProtocol)
574{
575 // TODO this could be improved to read the "no_proxy" env variable
576 InternetProxyServer aProxy;
577 OUString protocolLower = rProtocol.toAsciiLowerCase() + "_proxy";
578 OString protocolLowerStr = OUStringToOString( protocolLower, RTL_TEXTENCODING_ASCII_US );
579 const char* pEnvProxy = getenv(protocolLowerStr.getStr());
580 if (!pEnvProxy)
581 return aProxy;
582 // expecting something like "https://example.ct:80"
583 OUString tmp = OUString::createFromAscii(pEnvProxy);
584 if (tmp.getLength() < (rProtocol.getLength() + 3))
585 return aProxy;
586 tmp = tmp.copy(rProtocol.getLength() + 3);
587 sal_Int32 x = tmp.indexOf(':');
588 if (x == -1)
589 return aProxy;
590 int nPort = o3tl::toInt32(tmp.subView(x + 1));
591 if (nPort == 0)
592 return aProxy;
593 aProxy.aName = tmp.copy(0, x);
594 aProxy.nPort = nPort;
595 return aProxy;
596}
597
598#endif // else .. _WIN32
599}
600
602 const OUString & rProtocol,
603 const OUString & rHost,
604 sal_Int32 nPort ) const
605{
606 osl::Guard< osl::Mutex > aGuard( m_aMutex );
607
609 {
610 // Never use proxy.
611 return m_aEmptyProxy;
612 }
613
614 // If get from system
615 if (m_nProxyType == ProxyType::Automatic && !rHost.isEmpty())
616 {
617#ifdef _WIN32
618 InternetProxyServer aProxy(GetPACProxy(rProtocol, rHost, nPort));
619#else
620 InternetProxyServer aProxy(GetUnixSystemProxy(rProtocol));
621#endif // _WIN32
622 if (!aProxy.aName.isEmpty())
623 return aProxy;
624 }
625
626 if ( !rHost.isEmpty() && !m_aNoProxyList.empty() )
627 {
628
629 // First, try direct hostname match - #110515#
630
631
632 if ( !shouldUseProxy( rHost, nPort, false ) )
633 return m_aEmptyProxy;
634
635
636 // Second, try match against full qualified hostname - #104401#
637
638
639 OUString aHost;
640
641 if ( ( rHost.getLength() > 1 ) &&
642 ( rHost[ 0 ] == '[' ))
643 {
644 // host is given as numeric IPv6 address. name resolution
645 // functions need hostname without square brackets.
646 aHost = rHost.copy( 1, rHost.getLength() - 2 );
647 }
648 else
649 {
650 aHost = rHost;
651 }
652
653 OUString aFullyQualifiedHost;
654 if ( !m_aHostnames.get( aHost, aFullyQualifiedHost ) )
655 {
656 // This might be quite expensive (DNS lookup).
657 const osl::SocketAddr aAddr( aHost, nPort );
658 aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase();
659 m_aHostnames.put( aHost, aFullyQualifiedHost );
660 }
661
662 // Error resolving name? -> fallback.
663 if ( aFullyQualifiedHost.isEmpty() )
664 aFullyQualifiedHost = aHost;
665
666 if ( aFullyQualifiedHost != aHost )
667 {
668 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, false ) )
669 return m_aEmptyProxy;
670 }
671
672
673 // Third, try match of fully qualified entries in no-proxy list
674 // against full qualified hostname
675
676 // Example:
677 // list: staroffice-doc -> full: xyz.germany.sun.com
678 // in: staroffice-doc.germany.sun.com -> full: xyz.germany.sun.com
679
680
681 if ( !shouldUseProxy( aFullyQualifiedHost, nPort, true ) )
682 return m_aEmptyProxy;
683 }
684
685 if ( rProtocol.toAsciiLowerCase() == "ftp" )
686 {
687 if ( !m_aFtpProxy.aName.isEmpty() && m_aFtpProxy.nPort >= 0 )
688 return m_aFtpProxy;
689 }
690 else if ( rProtocol.toAsciiLowerCase() == "https" )
691 {
692 if ( !m_aHttpsProxy.aName.isEmpty() )
693 return m_aHttpsProxy;
694 }
695 else if ( !m_aHttpProxy.aName.isEmpty() )
696 {
697 // All other protocols use the HTTP proxy.
698 return m_aHttpProxy;
699 }
700 return m_aEmptyProxy;
701}
702
703// virtual
705 const util::ChangesEvent& Event )
706{
707 osl::Guard< osl::Mutex > aGuard( m_aMutex );
708
709 for ( const util::ElementChange& rElem : Event.Changes )
710 {
711 OUString aKey;
712 if ( ( rElem.Accessor >>= aKey ) && !aKey.isEmpty() )
713 {
714 if ( aKey == PROXY_TYPE_KEY )
715 {
716 sal_Int32 tmp;
717 if ( !( rElem.Element >>= tmp ) )
718 {
719 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
720 "Error getting config item value!" );
721 }
722 else
723 m_nProxyType = static_cast<ProxyType>(tmp);
724 }
725 else if ( aKey == NO_PROXY_LIST_KEY )
726 {
727 OUString aNoProxyList;
728 if ( !( rElem.Element >>= aNoProxyList ) )
729 {
730 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
731 "Error getting config item value!" );
732 }
733
734 setNoProxyList( aNoProxyList );
735 }
736 else if ( aKey == HTTP_PROXY_NAME_KEY )
737 {
738 if ( !( rElem.Element >>= m_aHttpProxy.aName ) )
739 {
740 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
741 "Error getting config item value!" );
742 }
743 }
744 else if ( aKey == HTTP_PROXY_PORT_KEY )
745 {
746 if ( !( rElem.Element >>= m_aHttpProxy.nPort ) )
747 {
748 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
749 "Error getting config item value!" );
750 }
751
752 if ( m_aHttpProxy.nPort == -1 )
753 m_aHttpProxy.nPort = 80; // standard HTTP port.
754 }
755 else if ( aKey == HTTPS_PROXY_NAME_KEY )
756 {
757 if ( !( rElem.Element >>= m_aHttpsProxy.aName ) )
758 {
759 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
760 "Error getting config item value!" );
761 }
762 }
763 else if ( aKey == HTTPS_PROXY_PORT_KEY )
764 {
765 if ( !( rElem.Element >>= m_aHttpsProxy.nPort ) )
766 {
767 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
768 "Error getting config item value!" );
769 }
770
771 if ( m_aHttpsProxy.nPort == -1 )
772 m_aHttpsProxy.nPort = 443; // standard HTTPS port.
773 }
774 else if ( aKey == FTP_PROXY_NAME_KEY )
775 {
776 if ( !( rElem.Element >>= m_aFtpProxy.aName ) )
777 {
778 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
779 "Error getting config item value!" );
780 }
781 }
782 else if ( aKey == FTP_PROXY_PORT_KEY )
783 {
784 if ( !( rElem.Element >>= m_aFtpProxy.nPort ) )
785 {
786 OSL_FAIL( "InternetProxyDecider - changesOccurred - "
787 "Error getting config item value!" );
788 }
789 }
790 }
791 }
792}
793
794
795// virtual
796void SAL_CALL InternetProxyDecider_Impl::disposing(const lang::EventObject&)
797{
798 if ( m_xNotifier.is() )
799 {
800 osl::Guard< osl::Mutex > aGuard( m_aMutex );
801
802 if ( m_xNotifier.is() )
803 m_xNotifier.clear();
804 }
805}
806
807
809 const OUString & rNoProxyList )
810{
811 osl::Guard< osl::Mutex > aGuard( m_aMutex );
812
813 m_aNoProxyList.clear();
814
815 if ( rNoProxyList.isEmpty() )
816 return;
817
818 // List of connection endpoints hostname[:port],
819 // separated by semicolon. Wildcards allowed.
820
821 sal_Int32 nPos = 0;
822 sal_Int32 nEnd = rNoProxyList.indexOf( ';' );
823 sal_Int32 nLen = rNoProxyList.getLength();
824
825 do
826 {
827 if ( nEnd == -1 )
828 nEnd = nLen;
829
830 OUString aToken = rNoProxyList.copy( nPos, nEnd - nPos );
831
832 if ( !aToken.isEmpty() )
833 {
834 OUString aServer;
835 OUString aPort;
836
837 // numerical IPv6 address?
838 bool bIPv6Address = false;
839 sal_Int32 nClosedBracketPos = aToken.indexOf( ']' );
840 if ( nClosedBracketPos == -1 )
841 nClosedBracketPos = 0;
842 else
843 bIPv6Address = true;
844
845 sal_Int32 nColonPos = aToken.indexOf( ':', nClosedBracketPos );
846 if ( nColonPos == -1 )
847 {
848 // No port given, server pattern equals current token
849 aPort = "*";
850 if ( aToken.indexOf( '*' ) == -1 )
851 {
852 // pattern describes exactly one server
853 aServer = aToken;
854 }
855
856 aToken += ":*";
857 }
858 else
859 {
860 // Port given, extract server pattern
861 sal_Int32 nAsteriskPos = aToken.indexOf( '*' );
862 aPort = aToken.copy( nColonPos + 1 );
863 if ( nAsteriskPos < nColonPos )
864 {
865 // pattern describes exactly one server
866 aServer = aToken.copy( 0, nColonPos );
867 }
868 }
869
870 OUStringBuffer aFullyQualifiedHost;
871 if ( !aServer.isEmpty() )
872 {
873 // Remember fully qualified server name if current list
874 // entry specifies exactly one non-fully qualified server
875 // name.
876
877 // remove square brackets from host name in case it's
878 // a numerical IPv6 address.
879 if ( bIPv6Address )
880 aServer = aServer.copy( 1, aServer.getLength() - 2 );
881
882 // This might be quite expensive (DNS lookup).
883 const osl::SocketAddr aAddr( aServer, 0 );
884 OUString aTmp = aAddr.getHostname().toAsciiLowerCase();
885 if ( aTmp != aServer.toAsciiLowerCase() )
886 {
887 if ( bIPv6Address )
888 aFullyQualifiedHost.append( "[" + aTmp + "]" );
889 else
890 aFullyQualifiedHost.append( aTmp );
891 aFullyQualifiedHost.append( ":" + aPort );
892 }
893 }
894
895 m_aNoProxyList.emplace_back( WildCard( aToken ),
896 WildCard( aFullyQualifiedHost ) );
897 }
898
899 if ( nEnd != nLen )
900 {
901 nPos = nEnd + 1;
902 nEnd = rNoProxyList.indexOf( ';', nPos );
903 }
904 }
905 while ( nEnd != nLen );
906}
907
908} // namespace proxydecider_impl
909
910
911// InternetProxyDecider Implementation.
912
913
915 const uno::Reference< uno::XComponentContext>& rxContext )
916: m_xImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxContext ) )
917{
918}
919
920
922{
923 // Break circular reference between config listener and notifier.
924 m_xImpl->dispose();
925}
926
927
928bool InternetProxyDecider::shouldUseProxy( const OUString & rProtocol,
929 const OUString & rHost,
930 sal_Int32 nPort ) const
931{
932 const InternetProxyServer & rData = m_xImpl->getProxy( rProtocol,
933 rHost,
934 nPort );
935 return !rData.aName.isEmpty();
936}
937
938
940 const OUString & rProtocol,
941 const OUString & rHost,
942 sal_Int32 nPort ) const
943{
944 return m_xImpl->getProxy( rProtocol, rHost, nPort );
945}
946
947} // namespace ucbhelper
948
949/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool Matches(std::u16string_view rStr) const
InternetProxyServer getProxy(const OUString &rProtocol, const OUString &rHost, sal_Int32 nPort) const
Returns the proxy server to be used.
rtl::Reference< proxydecider_impl::InternetProxyDecider_Impl > m_xImpl
InternetProxyDecider(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
Constructor.
bool shouldUseProxy(const OUString &rProtocol, const OUString &rHost, sal_Int32 nPort) const
Informs whether a proxy server should be used.
void setNoProxyList(const OUString &rNoProxyList)
InternetProxyServer getProxy(const OUString &rProtocol, const OUString &rHost, sal_Int32 nPort) const
bool shouldUseProxy(std::u16string_view rHost, sal_Int32 nPort, bool bUseFullyQualified) const
InternetProxyDecider_Impl(const uno::Reference< uno::XComponentContext > &rxContext)
virtual void SAL_CALL disposing(const lang::EventObject &Source) override
uno::Reference< util::XChangesNotifier > m_xNotifier
virtual void SAL_CALL changesOccurred(const util::ChangesEvent &Event) override
Any value
float u
float x
#define TRUE
#define FALSE
Sequence< PropertyValue > aArguments
sal_uInt16 nPos
std::unique_ptr< sal_Int32[]> pData
constexpr OUStringLiteral aData
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
static bool getConfigInt32Value(const uno::Reference< container::XNameAccess > &xNameAccess, const OUString &key, sal_Int32 &value)
static bool getConfigStringValue(const uno::Reference< container::XNameAccess > &xNameAccess, const OUString &key, OUString &value)
constexpr OUStringLiteral NO_PROXY_LIST_KEY
constexpr OUStringLiteral HTTPS_PROXY_PORT_KEY
constexpr OUStringLiteral HTTP_PROXY_NAME_KEY
constexpr OUStringLiteral PROXY_TYPE_KEY
constexpr OUStringLiteral FTP_PROXY_NAME_KEY
constexpr OUStringLiteral FTP_PROXY_PORT_KEY
constexpr OUStringLiteral HTTP_PROXY_PORT_KEY
OString m_aWildString
constexpr OUStringLiteral HTTPS_PROXY_NAME_KEY
constexpr OUStringLiteral CONFIG_ROOT_KEY
std::deque< HostListEntry > m_aHostList
This struct describes a proxy server.
sal_Int32 nPort
The port of the proxy server.
OUString aName
The name of the proxy server.
bool hasValue()
size_t pos
std::unique_ptr< char[]> aBuffer