15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NET_PROXY_DHCP_PROXY_SCRIPT_ADAPTER_FETCHER_WIN_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NET_PROXY_DHCP_PROXY_SCRIPT_ADAPTER_FETCHER_WIN_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/weak_ptr.h"
135e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string16.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/non_thread_safe.h"
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/completion_callback.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_export.h"
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace base {
21424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)class TaskRunner;
22424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
23424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ProxyScriptFetcher;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class URLRequestContext;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For a given adapter, this class takes care of first doing a DHCP lookup
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to get the PAC URL, then if there is one, trying to fetch it.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NET_EXPORT_PRIVATE DhcpProxyScriptAdapterFetcher
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::SupportsWeakPtr<DhcpProxyScriptAdapterFetcher>,
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NON_EXPORTED_BASE(public base::NonThreadSafe) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |url_request_context| must outlive DhcpProxyScriptAdapterFetcher.
36424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // |task_runner| will be used to post tasks to a thread.
37424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DhcpProxyScriptAdapterFetcher(URLRequestContext* url_request_context,
38424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                scoped_refptr<base::TaskRunner> task_runner);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~DhcpProxyScriptAdapterFetcher();
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Starts a fetch.  On completion (but not cancellation), |callback|
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be invoked with the network error indicating success or failure
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of fetching a DHCP-configured PAC file on this adapter.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On completion, results can be obtained via |GetPacScript()|, |GetPacURL()|.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // You may only call Fetch() once on a given instance of
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DhcpProxyScriptAdapterFetcher.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Fetch(const std::string& adapter_name,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const net::CompletionCallback& callback);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cancels the fetch on this adapter.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Cancel();
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if in the FINISH state (not CANCEL).
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool DidFinish() const;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the network error indicating the result of the fetch. Will
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // return IO_PENDING until the fetch is complete or cancelled. This is
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the same network error passed to the |callback| provided to |Fetch()|.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual int GetResult() const;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the contents of the PAC file retrieved.  Only valid if
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |IsComplete()| is true.  Returns the empty string if |GetResult()|
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returns anything other than OK.
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual base::string16 GetPacScript() const;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the PAC URL retrieved from DHCP.  Only guaranteed to be
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // valid if |IsComplete()| is true.  Returns an empty URL if no URL was
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // configured in DHCP.  May return a valid URL even if |result()| does
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not return OK (this would indicate that we found a URL configured in
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DHCP but failed to download it).
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual GURL GetPacURL() const;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the PAC URL configured in DHCP for the given |adapter_name|, or
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the empty string if none is configured.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This function executes synchronously due to limitations of the Windows
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DHCP client API.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static std::string GetPacURLFromDhcp(const std::string& adapter_name);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Sanitizes a string returned via the DHCP API.
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static std::string SanitizeDhcpApiString(const char* data,
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           size_t count_bytes);
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the state machine for fetching from a given adapter.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The state machine goes from START->WAIT_DHCP when it starts
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a worker thread to fetch the PAC URL from DHCP.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In state WAIT_DHCP, if the DHCP query finishes and has no URL, it
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // moves to state FINISH.  If there is a URL, it starts a
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ProxyScriptFetcher to fetch it and moves to state WAIT_URL.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It goes from WAIT_URL->FINISH when the ProxyScriptFetcher completes.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In state FINISH, completion is indicated to the outer class, with
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the results of the fetch if a PAC script was successfully fetched.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In state WAIT_DHCP, our timeout occurring can push us to FINISH.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In any state except FINISH, a call to Cancel() will move to state
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CANCEL and cause all outstanding work to be cancelled or its
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // results ignored when available.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum State {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATE_START,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATE_WAIT_DHCP,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATE_WAIT_URL,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATE_FINISH,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATE_CANCEL,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  State state() const;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This inner class encapsulates work done on a worker pool thread.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // By using a separate object, we can keep the main object completely
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread safe and let it be non-refcounted.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class NET_EXPORT_PRIVATE DhcpQuery
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : public base::RefCountedThreadSafe<DhcpQuery> {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public:
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DhcpQuery();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    virtual ~DhcpQuery();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This method should run on a worker pool thread, via PostTaskAndReply.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // After it has run, the |url()| method on this object will return the
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL retrieved.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void GetPacURLForAdapter(const std::string& adapter_name);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Returns the URL retrieved for the given adapter, once the task has run.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& url() const;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   protected:
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Virtual method introduced to allow unit testing.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    virtual std::string ImplGetPacURLFromDhcp(const std::string& adapter_name);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   private:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The URL retrieved for the given adapter.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string url_;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(DhcpQuery);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Virtual methods introduced to allow unit testing.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ProxyScriptFetcher* ImplCreateScriptFetcher();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual DhcpQuery* ImplCreateDhcpQuery();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual base::TimeDelta ImplGetTimeout() const;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Event/state transition handlers
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnDhcpQueryDone(scoped_refptr<DhcpQuery> dhcp_query);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnTimeout();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnFetcherDone(int result);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void TransitionToFinish();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
156424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // TaskRunner for posting tasks to a worker thread.
157424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  scoped_refptr<base::TaskRunner> task_runner_;
158424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Current state of this state machine.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  State state_;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A network error indicating result of operation.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result_;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Empty string or the PAC script downloaded.
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::string16 pac_script_;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Empty URL or the PAC URL configured in DHCP.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL pac_url_;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Callback to let our client know we're done. Invalid in states
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // START, FINISH and CANCEL.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::CompletionCallback callback_;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fetcher to retrieve PAC files once URL is known.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ProxyScriptFetcher> script_fetcher_;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Implements a timeout on the call to the Win32 DHCP API.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::OneShotTimer<DhcpProxyScriptAdapterFetcher> wait_timer_;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRequestContext* const url_request_context_;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_IMPLICIT_CONSTRUCTORS(DhcpProxyScriptAdapterFetcher);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // NET_PROXY_DHCP_PROXY_SCRIPT_ADAPTER_FETCHER_WIN_H_
189