text: // Copyright 2020 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef NET_PROXY_RESOLUTION_WIN_WINDOWS_SYSTEM_PROXY_RESOLVER_H_
  #define NET_PROXY_RESOLUTION_WIN_WINDOWS_SYSTEM_PROXY_RESOLVER_H_
  
  #include <windows.h>
  #include <winhttp.h>
  
  #include <memory>
  #include <string>
  #include <unordered_map>
  
  #include "base/callback.h"
  #include "base/compiler_specific.h"
  #include "base/memory/ref_counted.h"
  #include "base/sequence_checker.h"
  #include "base/sequenced_task_runner.h"
  #include "net/base/net_export.h"
  #include "net/proxy_resolution/proxy_list.h"
  
  namespace net {
  
  class WindowsSystemProxyResolutionRequest;
  class WinHttpAPIWrapper;
  
  // This provides a layer of abstraction between calling code Windows-specific
  // code. It is shared between the WindowsSystemProxyResolutionService and
  // inflight WinHttp callbacks. Internally, it takes care of all interaction with
  // WinHttp. The only time this object is ever access outside of its sequence is
  // during the WinHttp callback. For the sake of that callback, this must be
  // RefcountedThreadSafe.
  class NET_EXPORT WindowsSystemProxyResolver
      : public base::RefCountedThreadSafe<WindowsSystemProxyResolver> {
   public:
    static scoped_refptr<WindowsSystemProxyResolver>
    CreateWindowsSystemProxyResolver();
  
    WindowsSystemProxyResolver(const WindowsSystemProxyResolver&) = delete;
    WindowsSystemProxyResolver& operator=(const WindowsSystemProxyResolver&) =
        delete;
  
    // This will first fetch the current system proxy settings by calling into
    // WinHttpGetIEProxyConfigForCurrentUser() and then resolve the proxy using
    // those settings as an input into WinHttpGetProxyForUrlEx().
    virtual bool GetProxyForUrl(
        WindowsSystemProxyResolutionRequest* callback_target,
        const std::string& url) WARN_UNUSED_RESULT;
  
    // After calling GetProxyForUrl(), a |callback_target| is saved internally for
    // when proxy resolution is complete. When a
    // WindowsSystemProxyResolutionRequest wants to avoid receiving a callback,
    // it must remove itself from the list of pending callback targets.
    virtual void RemovePendingCallbackTarget(
        WindowsSystemProxyResolutionRequest* callback_target);
    virtual bool HasPendingCallbackTarget(
        WindowsSystemProxyResolutionRequest* callback_target) const
        WARN_UNUSED_RESULT;
  
   protected:
    explicit WindowsSystemProxyResolver(
        std::unique_ptr<WinHttpAPIWrapper> winhttp_api_wrapper);
    virtual ~WindowsSystemProxyResolver();
  
   private:
    friend class base::RefCountedThreadSafe<WindowsSystemProxyResolver>;
    friend class WindowsSystemProxyResolverTest;
  
    // Sets up the WinHttp session that will be used throughout the lifetime of
    // this object.
    bool Initialize();
  
    // These will interact with |pending_callback_target_map_|.
    void AddPendingCallbackTarget(
        WindowsSystemProxyResolutionRequest* callback_target,
        HINTERNET handle);
    WindowsSystemProxyResolutionRequest* LookupCallbackTargetFromResolverHandle(
        HINTERNET resolver_handle) const;
  
    // This is the callback provided to WinHttp. Once a call to resolve a proxy
    // succeeds or errors out, it'll call into here with |context| being a pointer
    // to a WindowsSystemProxyResolver that has been kept alive. This callback can
    // hit in any thread and will immediately post a task to the right sequence.
    static void __stdcall WinHttpStatusCallback(HINTERNET resolver_handle,
                                                DWORD_PTR context,
                                                DWORD status,
                                                void* info,
                                                DWORD info_len);
  
    // Called from WinHttpStatusCallback on the right sequence. This will make
    // decisions about what to do from the results of the proxy resolution call.
    // Note that the WindowsSystemProxyResolutionRequest that asked for this proxy
    // may have decided they no longer need an answer (ex: the request has gone
    // away), so this function has to deal with that situation too.
    void DoWinHttpStatusCallback(HINTERNET resolver_handle,
                                 DWORD status,
                                 int windows_error);
  
    // On a successful call to WinHttpGetProxyForUrlEx(), this translates WinHttp
    // results into Chromium-friendly structures before notifying the right
    // WindowsSystemProxyResolutionRequest.
    void GetProxyResultForCallbackTarget(
        WindowsSystemProxyResolutionRequest* callback_target,
        HINTERNET resolver_handle);
  
    // On a failed call to WinHttpGetProxyForUrlEx(), this will notify the right
    // WindowsSystemProxyResolutionRequest of the error.
    void HandleErrorForCallbackTarget(
        WindowsSystemProxyResolutionRequest* callback_target,
        int windows_error);
  
    // This is a thin wrapper over WinHttp APIs that may be overridden for
    // testing.
    std::unique_ptr<WinHttpAPIWrapper> winhttp_api_wrapper_;
  
    // This is the mapping of WindowsSystemProxyResolutionRequest objects that
    // called GetProxyForUrl() to the handle that's being used for their proxy
    // resolution call. Upon receiving a callback from WinHttp (which includes an
    // HINTERNET handle), a reverse lookup here will get the right
    // WindowsSystemProxyResolutionRequest to use.
    std::unordered_map<WindowsSystemProxyResolutionRequest*, HINTERNET>
        pending_callback_target_map_;
  
    SEQUENCE_CHECKER(sequence_checker_);
    scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
  };
  
  }  // namespace net
  
  #endif  // NET_PROXY_RESOLUTION_WIN_WINDOWS_SYSTEM_PROXY_RESOLVER_H_
  