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