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