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
3// found in the LICENSE file.
4
5#ifndef NET_PROXY_MOCK_PROXY_RESOLVER_H_
6#define NET_PROXY_MOCK_PROXY_RESOLVER_H_
7
8#include <vector>
9
10#include "base/logging.h"
11#include "base/message_loop.h"
12#include "googleurl/src/gurl.h"
13#include "net/base/net_errors.h"
14#include "net/proxy/proxy_resolver.h"
15
16namespace net {
17
18// Asynchronous mock proxy resolver. All requests complete asynchronously,
19// user must call Request::CompleteNow() on a pending request to signal it.
20class MockAsyncProxyResolverBase : public ProxyResolver {
21 public:
22  class Request : public base::RefCounted<Request> {
23   public:
24    Request(MockAsyncProxyResolverBase* resolver,
25            const GURL& url,
26            ProxyInfo* results,
27            CompletionCallback* callback)
28        : resolver_(resolver),
29          url_(url),
30          results_(results),
31          callback_(callback),
32          origin_loop_(MessageLoop::current()) {
33    }
34
35    const GURL& url() const { return url_; }
36    ProxyInfo* results() const { return results_; }
37    CompletionCallback* callback() const { return callback_; }
38
39    void CompleteNow(int rv) {
40      CompletionCallback* callback = callback_;
41
42      // May delete |this|.
43      resolver_->RemovePendingRequest(this);
44
45      callback->Run(rv);
46    }
47
48   private:
49    friend class base::RefCounted<Request>;
50
51    ~Request() {}
52
53    MockAsyncProxyResolverBase* resolver_;
54    const GURL url_;
55    ProxyInfo* results_;
56    CompletionCallback* callback_;
57    MessageLoop* origin_loop_;
58  };
59
60  class SetPacScriptRequest {
61   public:
62    SetPacScriptRequest(MockAsyncProxyResolverBase* resolver,
63                        const GURL& pac_url,
64                        const std::string& pac_bytes,
65                        CompletionCallback* callback)
66        : resolver_(resolver),
67          pac_url_(pac_url),
68          pac_bytes_(pac_bytes),
69          callback_(callback),
70          origin_loop_(MessageLoop::current()) {
71    }
72
73    const GURL& pac_url() const { return pac_url_; }
74    const std::string& pac_bytes() const { return pac_bytes_; }
75
76    void CompleteNow(int rv) {
77       CompletionCallback* callback = callback_;
78
79      // Will delete |this|.
80      resolver_->RemovePendingSetPacScriptRequest(this);
81
82      callback->Run(rv);
83    }
84
85   private:
86    MockAsyncProxyResolverBase* resolver_;
87    const GURL pac_url_;
88    const std::string pac_bytes_;
89    CompletionCallback* callback_;
90    MessageLoop* origin_loop_;
91  };
92
93  typedef std::vector<scoped_refptr<Request> > RequestsList;
94
95  // ProxyResolver implementation:
96  virtual int GetProxyForURL(const GURL& url,
97                             ProxyInfo* results,
98                             CompletionCallback* callback,
99                             RequestHandle* request_handle,
100                             LoadLog* /*load_log*/) {
101    scoped_refptr<Request> request = new Request(this, url, results, callback);
102    pending_requests_.push_back(request);
103
104    if (request_handle)
105      *request_handle = reinterpret_cast<RequestHandle>(request.get());
106
107    // Test code completes the request by calling request->CompleteNow().
108    return ERR_IO_PENDING;
109  }
110
111  virtual void CancelRequest(RequestHandle request_handle) {
112    scoped_refptr<Request> request = reinterpret_cast<Request*>(request_handle);
113    cancelled_requests_.push_back(request);
114    RemovePendingRequest(request);
115  }
116
117  virtual int SetPacScript(const GURL& pac_url,
118                           const std::string& pac_bytes,
119                           CompletionCallback* callback) {
120    DCHECK(!pending_set_pac_script_request_.get());
121    pending_set_pac_script_request_.reset(
122        new SetPacScriptRequest(this, pac_url, pac_bytes, callback));
123    // Finished when user calls SetPacScriptRequest::CompleteNow().
124    return ERR_IO_PENDING;
125  }
126
127  virtual void CancelSetPacScript() {
128    // Do nothing (caller was responsible for completing the request).
129  }
130
131  const RequestsList& pending_requests() const {
132    return pending_requests_;
133  }
134
135  const RequestsList& cancelled_requests() const {
136    return cancelled_requests_;
137  }
138
139  SetPacScriptRequest* pending_set_pac_script_request() const {
140    return pending_set_pac_script_request_.get();
141  }
142
143  void RemovePendingRequest(Request* request) {
144    RequestsList::iterator it = std::find(
145        pending_requests_.begin(), pending_requests_.end(), request);
146    DCHECK(it != pending_requests_.end());
147    pending_requests_.erase(it);
148  }
149
150  void RemovePendingSetPacScriptRequest(SetPacScriptRequest* request) {
151    DCHECK_EQ(request, pending_set_pac_script_request());
152    pending_set_pac_script_request_.reset();
153  }
154
155 protected:
156  explicit MockAsyncProxyResolverBase(bool expects_pac_bytes)
157      : ProxyResolver(expects_pac_bytes) {}
158
159 private:
160  RequestsList pending_requests_;
161  RequestsList cancelled_requests_;
162  scoped_ptr<SetPacScriptRequest> pending_set_pac_script_request_;
163};
164
165class MockAsyncProxyResolver : public MockAsyncProxyResolverBase {
166 public:
167  MockAsyncProxyResolver()
168      : MockAsyncProxyResolverBase(false /*expects_pac_bytes*/) {}
169};
170
171class MockAsyncProxyResolverExpectsBytes : public MockAsyncProxyResolverBase {
172 public:
173  MockAsyncProxyResolverExpectsBytes()
174      : MockAsyncProxyResolverBase(true /*expects_pac_bytes*/) {}
175};
176
177}  // namespace net
178
179#endif  // NET_PROXY_MOCK_PROXY_RESOLVER_H_
180