| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef NET_PROXY_PROXY_SERVICE_H_ | 5 #ifndef NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_ |
| 6 #define NET_PROXY_PROXY_SERVICE_H_ | 6 #define NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_ |
| 7 | 7 |
| 8 #include <deque> | 8 #include <deque> |
| 9 #include <string> | 9 #include <string> |
| 10 | 10 |
| 11 #include "base/ref_counted.h" | 11 #include "base/ref_counted.h" |
| 12 #include "base/scoped_ptr.h" | 12 #include "base/scoped_ptr.h" |
| 13 #include "base/thread.h" | 13 #include "net/proxy/proxy_resolver.h" |
| 14 #include "base/waitable_event.h" | |
| 15 #include "net/base/completion_callback.h" | |
| 16 #include "net/proxy/proxy_server.h" | |
| 17 #include "net/proxy/proxy_info.h" | |
| 18 | 14 |
| 19 class GURL; | 15 namespace base { |
| 20 class URLRequestContext; | 16 class Thread; |
| 17 } // namespace base |
| 21 | 18 |
| 22 namespace net { | 19 namespace net { |
| 23 | 20 |
| 24 class ProxyScriptFetcher; | 21 // ProxyResolver implementation that wraps a synchronous ProxyResolver, and |
| 25 class ProxyConfigService; | 22 // runs it on a single worker thread. If multiple requests accumulate, they |
| 26 class ProxyResolver; | 23 // are serviced in FIFO order. |
| 24 class SingleThreadedProxyResolver : public ProxyResolver { |
| 25 public: |
| 27 | 26 |
| 28 // This class can be used to resolve the proxy server to use when loading a | 27 // |resolver| is a synchronous ProxyResolver implementation. It doesn't |
| 29 // HTTP(S) URL. It uses the given ProxyResolver to handle the actual proxy | 28 // have to be thread-safe, since it is run on exactly one thread. The |
| 30 // resolution. See ProxyResolverWinHttp for example. | 29 // constructor takes ownership of |resolver|. |
| 31 class ProxyService { | 30 explicit SingleThreadedProxyResolver(ProxyResolver* resolver); |
| 32 public: | |
| 33 // The instance takes ownership of |config_service| and |resolver|. | |
| 34 ProxyService(ProxyConfigService* config_service, | |
| 35 ProxyResolver* resolver); | |
| 36 | 31 |
| 37 ~ProxyService(); | 32 virtual ~SingleThreadedProxyResolver(); |
| 38 | 33 |
| 39 // Used internally to handle PAC queries. | 34 // ProxyResolver implementation: |
| 40 class PacRequest; | 35 virtual int GetProxyForURL(const GURL& url, |
| 36 ProxyInfo* results, |
| 37 CompletionCallback* callback, |
| 38 RequestHandle* request); |
| 39 virtual void CancelRequest(RequestHandle request); |
| 41 | 40 |
| 42 // Returns ERR_IO_PENDING if the proxy information could not be provided | 41 protected: |
| 43 // synchronously, to indicate that the result will be available when the | 42 // The wrapped (synchronous) ProxyResolver. |
| 44 // callback is run. The callback is run on the thread that calls | 43 ProxyResolver* resolver() { return resolver_.get(); } |
| 45 // ResolveProxy. | |
| 46 // | |
| 47 // The caller is responsible for ensuring that |results| and |callback| | |
| 48 // remain valid until the callback is run or until |pac_request| is cancelled | |
| 49 // via CancelPacRequest. |pac_request| is only valid while the completion | |
| 50 // callback is still pending. NULL can be passed for |pac_request| if | |
| 51 // the caller will not need to cancel the request. | |
| 52 // | |
| 53 // We use the three possible proxy access types in the following order, and | |
| 54 // we only use one of them (no falling back to other access types if the | |
| 55 // chosen one doesn't work). | |
| 56 // 1. named proxy | |
| 57 // 2. PAC URL | |
| 58 // 3. WPAD auto-detection | |
| 59 // | |
| 60 int ResolveProxy(const GURL& url, | |
| 61 ProxyInfo* results, | |
| 62 CompletionCallback* callback, | |
| 63 PacRequest** pac_request); | |
| 64 | |
| 65 // This method is called after a failure to connect or resolve a host name. | |
| 66 // It gives the proxy service an opportunity to reconsider the proxy to use. | |
| 67 // The |results| parameter contains the results returned by an earlier call | |
| 68 // to ResolveProxy. The semantics of this call are otherwise similar to | |
| 69 // ResolveProxy. | |
| 70 // | |
| 71 // NULL can be passed for |pac_request| if the caller will not need to | |
| 72 // cancel the request. | |
| 73 // | |
| 74 // Returns ERR_FAILED if there is not another proxy config to try. | |
| 75 // | |
| 76 int ReconsiderProxyAfterError(const GURL& url, | |
| 77 ProxyInfo* results, | |
| 78 CompletionCallback* callback, | |
| 79 PacRequest** pac_request); | |
| 80 | |
| 81 // Call this method with a non-null |pac_request| to cancel the PAC request. | |
| 82 void CancelPacRequest(PacRequest* pac_request); | |
| 83 | |
| 84 // Sets the ProxyScriptFetcher dependency. This is needed if the ProxyResolver | |
| 85 // is of type ProxyResolverWithoutFetch. ProxyService takes ownership of | |
| 86 // |proxy_script_fetcher|. | |
| 87 void SetProxyScriptFetcher(ProxyScriptFetcher* proxy_script_fetcher); | |
| 88 | |
| 89 // Tells this ProxyService to start using a new ProxyConfigService to | |
| 90 // retrieve its ProxyConfig from. The new ProxyConfigService will immediately | |
| 91 // be queried for new config info which will be used for all subsequent | |
| 92 // ResolveProxy calls. ProxyService takes ownership of | |
| 93 // |new_proxy_config_service|. | |
| 94 void ResetConfigService(ProxyConfigService* new_proxy_config_service); | |
| 95 | |
| 96 // Creates a proxy service using the specified settings. If |pc| is NULL then | |
| 97 // the system's default proxy settings will be used (on Windows this will | |
| 98 // use IE's settings). | |
| 99 // Iff |use_v8_resolver| is true, then the V8 implementation is | |
| 100 // used. | |
| 101 // |url_request_context| is only used when use_v8_resolver is true: | |
| 102 // it specifies the URL request context that will be used if a PAC | |
| 103 // script needs to be fetched. | |
| 104 // |io_loop| points to the IO thread's message loop. It is only used | |
| 105 // when pc is NULL. If both pc and io_loop are NULL, then monitoring | |
| 106 // of gconf setting changes will be disabled in | |
| 107 // ProxyConfigServiceLinux. | |
| 108 // ########################################################################## | |
| 109 // # See the warnings in net/proxy/proxy_resolver_v8.h describing the | |
| 110 // # multi-threading model. In order for this to be safe to use, *ALL* the | |
| 111 // # other V8's running in the process must use v8::Locker. | |
| 112 // ########################################################################## | |
| 113 static ProxyService* Create( | |
| 114 const ProxyConfig* pc, | |
| 115 bool use_v8_resolver, | |
| 116 URLRequestContext* url_request_context, | |
| 117 MessageLoop* io_loop); | |
| 118 | |
| 119 // Convenience method that creates a proxy service using the | |
| 120 // specified fixed settings. |pc| must not be NULL. | |
| 121 static ProxyService* CreateFixed(const ProxyConfig& pc); | |
| 122 | |
| 123 // Creates a proxy service that always fails to fetch the proxy configuration, | |
| 124 // so it falls back to direct connect. | |
| 125 static ProxyService* CreateNull(); | |
| 126 | 44 |
| 127 private: | 45 private: |
| 128 friend class PacRequest; | 46 // Refcounted helper class that bridges between origin thread and worker |
| 47 // thread. |
| 48 class Job; |
| 49 friend class Job; |
| 50 // FIFO queue that contains the in-progress job, and any pending jobs. |
| 51 typedef std::deque<scoped_refptr<Job> > PendingJobsQueue; |
| 129 | 52 |
| 130 // Creates a config service appropriate for this platform that fetches the | 53 base::Thread* thread() { return thread_.get(); } |
| 131 // system proxy settings. | |
| 132 static ProxyConfigService* CreateSystemProxyConfigService( | |
| 133 MessageLoop* io_loop); | |
| 134 | 54 |
| 135 // Creates a proxy resolver appropriate for this platform that doesn't rely | 55 // ProxyResolver implementation: |
| 136 // on V8. | 56 virtual void SetPacScriptByUrlInternal(const GURL& pac_url); |
| 137 static ProxyResolver* CreateNonV8ProxyResolver(); | 57 virtual void SetPacScriptByDataInternal(const std::string& bytes); |
| 138 | 58 |
| 139 ProxyResolver* resolver() { return resolver_.get(); } | 59 // Helper for shared code between SetPacScriptByUrlInternal() and |
| 140 base::Thread* pac_thread() { return pac_thread_.get(); } | 60 // SetPacScriptByDataInternal() -- the unused parameter is set to empty. |
| 61 void SetPacScriptHelper(const GURL& pac_url, const std::string& bytes); |
| 141 | 62 |
| 142 // Identifies the proxy configuration. | 63 // Starts the worker thread if it isn't already running. |
| 143 ProxyConfig::ID config_id() const { return config_.id(); } | 64 void EnsureThreadStarted(); |
| 144 | 65 |
| 145 // Returns true if we have called UpdateConfig() at least once. | 66 // Starts the next job from |pending_jobs_| if possible. |
| 146 bool config_has_been_initialized() const { | 67 void ProcessPendingJobs(); |
| 147 return config_.id() != ProxyConfig::INVALID_ID; | |
| 148 } | |
| 149 | 68 |
| 150 // Checks to see if the proxy configuration changed, and then updates config_ | 69 // Removes the front entry of the jobs queue. |expected_job| is our |
| 151 // to reference the new configuration. | 70 // expectation of what the front of the job queue is; it is only used by |
| 152 void UpdateConfig(); | 71 // DCHECK for verification purposes. |
| 72 void RemoveFrontOfJobsQueueAndStartNext(Job* expected_job); |
| 153 | 73 |
| 154 // Assign |config| as the current configuration. | 74 // The synchronous resolver implementation. |
| 155 void SetConfig(const ProxyConfig& config); | 75 scoped_ptr<ProxyResolver> resolver_; |
| 156 | 76 |
| 157 // Tries to update the configuration if it hasn't been checked in a while. | 77 // The thread where |resolver_| is run on. |
| 158 void UpdateConfigIfOld(); | 78 // Note that declaration ordering is important here. |thread_| needs to be |
| 79 // destroyed *before* |resolver_|, in case |resolver_| is currently |
| 80 // executing on |thread_|. |
| 81 scoped_ptr<base::Thread> thread_; |
| 159 | 82 |
| 160 // Returns true if this ProxyService is downloading a PAC script on behalf | 83 PendingJobsQueue pending_jobs_; |
| 161 // of ProxyResolverWithoutFetch. Resolve requests will be frozen until | |
| 162 // the fetch has completed. | |
| 163 bool IsFetchingPacScript() const { | |
| 164 return in_progress_fetch_config_id_ != ProxyConfig::INVALID_ID; | |
| 165 } | |
| 166 | |
| 167 // Callback for when the PAC script has finished downloading. | |
| 168 void OnScriptFetchCompletion(int result); | |
| 169 | |
| 170 // Returns ERR_IO_PENDING if the request cannot be completed synchronously. | |
| 171 // Otherwise it fills |result| with the proxy information for |url|. | |
| 172 // Completing synchronously means we don't need to query ProxyResolver. | |
| 173 // (ProxyResolver runs on PAC thread.) | |
| 174 int TryToCompleteSynchronously(const GURL& url, ProxyInfo* result); | |
| 175 | |
| 176 // Set |result| with the proxy to use for |url|, based on |rules|. | |
| 177 void ApplyProxyRules(const GURL& url, | |
| 178 const ProxyConfig::ProxyRules& rules, | |
| 179 ProxyInfo* result); | |
| 180 | |
| 181 // Starts the PAC thread if it isn't already running. | |
| 182 void InitPacThread(); | |
| 183 | |
| 184 // Starts the next request from |pending_requests_| is possible. | |
| 185 // |recent_req| is the request that just got added, or NULL. | |
| 186 void ProcessPendingRequests(PacRequest* recent_req); | |
| 187 | |
| 188 // Removes the front entry of the requests queue. |expected_req| is our | |
| 189 // expectation of what the front of the request queue is; it is only used by | |
| 190 // DCHECK for verification purposes. | |
| 191 void RemoveFrontOfRequestQueue(PacRequest* expected_req); | |
| 192 | |
| 193 // Called to indicate that a PacRequest completed. The |config_id| parameter | |
| 194 // indicates the proxy configuration that was queried. |result_code| is OK | |
| 195 // if the PAC file could be downloaded and executed. Otherwise, it is an | |
| 196 // error code, indicating a bad proxy configuration. | |
| 197 void DidCompletePacRequest(int config_id, int result_code); | |
| 198 | |
| 199 // Returns true if the URL passed in should not go through the proxy server. | |
| 200 // 1. If the bypass proxy list contains the string <local> and the URL | |
| 201 // passed in is a local URL, i.e. a URL without a DOT (.) | |
| 202 // 2. The URL matches one of the entities in the proxy bypass list. | |
| 203 bool ShouldBypassProxyForURL(const GURL& url); | |
| 204 | |
| 205 scoped_ptr<ProxyConfigService> config_service_; | |
| 206 scoped_ptr<ProxyResolver> resolver_; | |
| 207 scoped_ptr<base::Thread> pac_thread_; | |
| 208 | |
| 209 // We store the proxy config and a counter (ID) that is incremented each time | |
| 210 // the config changes. | |
| 211 ProxyConfig config_; | |
| 212 | |
| 213 // Increasing ID to give to the next ProxyConfig that we set. | |
| 214 int next_config_id_; | |
| 215 | |
| 216 // Indicates that the configuration is bad and should be ignored. | |
| 217 bool config_is_bad_; | |
| 218 | |
| 219 // The time when the proxy configuration was last read from the system. | |
| 220 base::TimeTicks config_last_update_time_; | |
| 221 | |
| 222 // Map of the known bad proxies and the information about the retry time. | |
| 223 ProxyRetryInfoMap proxy_retry_info_; | |
| 224 | |
| 225 // FIFO queue of pending/inprogress requests. | |
| 226 typedef std::deque<scoped_refptr<PacRequest> > PendingRequestsQueue; | |
| 227 PendingRequestsQueue pending_requests_; | |
| 228 | |
| 229 // The fetcher to use when downloading PAC scripts for the ProxyResolver. | |
| 230 // This dependency can be NULL if our ProxyResolver has no need for | |
| 231 // external PAC script fetching. | |
| 232 scoped_ptr<ProxyScriptFetcher> proxy_script_fetcher_; | |
| 233 | |
| 234 // Callback for when |proxy_script_fetcher_| is done. | |
| 235 CompletionCallbackImpl<ProxyService> proxy_script_fetcher_callback_; | |
| 236 | |
| 237 // The ID of the configuration for which we last downloaded a PAC script. | |
| 238 // If no PAC script has been fetched yet, will be ProxyConfig::INVALID_ID. | |
| 239 ProxyConfig::ID fetched_pac_config_id_; | |
| 240 | |
| 241 // The error corresponding with |fetched_pac_config_id_|, or OK. | |
| 242 int fetched_pac_error_; | |
| 243 | |
| 244 // The ID of the configuration for which we are currently downloading the | |
| 245 // PAC script. If no fetch is in progress, will be ProxyConfig::INVALID_ID. | |
| 246 ProxyConfig::ID in_progress_fetch_config_id_; | |
| 247 | |
| 248 // The results of the current in progress fetch, or empty string. | |
| 249 std::string in_progress_fetch_bytes_; | |
| 250 | |
| 251 DISALLOW_COPY_AND_ASSIGN(ProxyService); | |
| 252 }; | |
| 253 | |
| 254 // Wrapper for invoking methods on a ProxyService synchronously. | |
| 255 class SyncProxyServiceHelper | |
| 256 : public base::RefCountedThreadSafe<SyncProxyServiceHelper> { | |
| 257 public: | |
| 258 SyncProxyServiceHelper(MessageLoop* io_message_loop, | |
| 259 ProxyService* proxy_service); | |
| 260 | |
| 261 int ResolveProxy(const GURL& url, ProxyInfo* proxy_info); | |
| 262 int ReconsiderProxyAfterError(const GURL& url, ProxyInfo* proxy_info); | |
| 263 | |
| 264 private: | |
| 265 void StartAsyncResolve(const GURL& url); | |
| 266 void StartAsyncReconsider(const GURL& url); | |
| 267 | |
| 268 void OnCompletion(int result); | |
| 269 | |
| 270 MessageLoop* io_message_loop_; | |
| 271 ProxyService* proxy_service_; | |
| 272 | |
| 273 base::WaitableEvent event_; | |
| 274 CompletionCallbackImpl<SyncProxyServiceHelper> callback_; | |
| 275 ProxyInfo proxy_info_; | |
| 276 int result_; | |
| 277 }; | 84 }; |
| 278 | 85 |
| 279 } // namespace net | 86 } // namespace net |
| 280 | 87 |
| 281 #endif // NET_PROXY_PROXY_SERVICE_H_ | 88 #endif // NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_ |
| OLD | NEW |