1 // Copyright 2018 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 SERVICES_NETWORK_TEST_TEST_URL_LOADER_FACTORY_H_ 6 #define SERVICES_NETWORK_TEST_TEST_URL_LOADER_FACTORY_H_ 7 8 #include <map> 9 #include <string> 10 #include <vector> 11 12 #include "base/macros.h" 13 #include "base/memory/ref_counted.h" 14 #include "mojo/public/cpp/bindings/pending_receiver.h" 15 #include "mojo/public/cpp/bindings/pending_remote.h" 16 #include "mojo/public/cpp/bindings/receiver_set.h" 17 #include "mojo/public/cpp/bindings/remote.h" 18 #include "net/http/http_status_code.h" 19 #include "services/network/public/cpp/resource_request.h" 20 #include "services/network/public/mojom/url_loader.mojom.h" 21 #include "services/network/public/mojom/url_loader_factory.mojom.h" 22 #include "services/network/public/mojom/url_response_head.mojom-forward.h" 23 24 namespace network { 25 class WeakWrapperSharedURLLoaderFactory; 26 27 // A helper class to ease testing code that uses URLLoader interface. A test 28 // would pass this factory instead of the production factory to code, and 29 // would prime it with response data for arbitrary URLs. 30 class TestURLLoaderFactory : public mojom::URLLoaderFactory { 31 public: 32 struct PendingRequest { 33 PendingRequest(); 34 ~PendingRequest(); 35 PendingRequest(PendingRequest&& other); 36 PendingRequest& operator=(PendingRequest&& other); 37 38 mojo::Remote<mojom::URLLoaderClient> client; 39 ResourceRequest request; 40 uint32_t options; 41 }; 42 43 // Bitfield that is used with |SimulateResponseForPendingRequest()| to 44 // control which request is selected. 45 enum ResponseMatchFlags : uint32_t { 46 kMatchDefault = 0x0, 47 kUrlMatchPrefix = 0x1, // Whether URLs are a match if they start with the 48 // URL passed in to 49 // SimulateResponseForPendingRequest 50 kMostRecentMatch = 0x2, // Start with the most recent requests. 51 }; 52 53 // Flags used with |AddResponse| to control how it produces a response. 54 enum ResponseProduceFlags : uint32_t { 55 kResponseDefault = 0, 56 kResponseOnlyRedirectsNoDestination = 0x1, 57 kSendHeadersOnNetworkError = 0x2, 58 }; 59 60 TestURLLoaderFactory(); 61 ~TestURLLoaderFactory() override; 62 63 using Redirects = 64 std::vector<std::pair<net::RedirectInfo, mojom::URLResponseHeadPtr>>; 65 66 // Adds a response to be served. There is one unique response per URL, and if 67 // this method is called multiple times for the same URL the last response 68 // data is used. 69 // This can be called before or after a request is made. If it's called after, 70 // then pending requests will be "woken up". 71 void AddResponse(const GURL& url, 72 mojom::URLResponseHeadPtr head, 73 const std::string& content, 74 const URLLoaderCompletionStatus& status, 75 Redirects redirects = Redirects(), 76 ResponseProduceFlags rp_flags = kResponseDefault); 77 78 // Simpler version of above for the common case of success or error page. 79 void AddResponse(const std::string& url, 80 const std::string& content, 81 net::HttpStatusCode status = net::HTTP_OK); 82 83 // Returns true if there is a request for a given URL with a living client 84 // that did not produce a response yet. If |request_out| is non-null, 85 // it will give a const pointer to the request. 86 // WARNING: This does RunUntilIdle() first. 87 bool IsPending(const std::string& url, 88 const ResourceRequest** request_out = nullptr); 89 90 // Returns the total # of pending requests. 91 // WARNING: This does RunUntilIdle() first. 92 int NumPending(); 93 94 // Clear all the responses that were previously set. 95 void ClearResponses(); 96 97 using Interceptor = base::RepeatingCallback<void(const ResourceRequest&)>; 98 void SetInterceptor(const Interceptor& interceptor); 99 100 // Returns a mutable list of pending requests, for consumers that need direct 101 // access. It's recommended that consumers use AddResponse() rather than 102 // servicing requests themselves, whenever possible. pending_requests()103 std::vector<PendingRequest>* pending_requests() { return &pending_requests_; } 104 105 // Returns the PendingRequest instance available at the given index |index| 106 // or null if not existing. 107 PendingRequest* GetPendingRequest(size_t index); 108 109 // Sends a response for the first (oldest) pending request with URL |url|. 110 // Returns false if no such pending request exists. 111 // |flags| can be used to change the default behavior: 112 // - if kUrlMatchPrefix is set, the pending request is a match if its URL 113 // starts with |url| (instead of being equal to |url|). 114 // - if kMostRecentMatch is set, the most recent (instead of oldest) pending 115 // request matching is used. 116 bool SimulateResponseForPendingRequest( 117 const GURL& url, 118 const network::URLLoaderCompletionStatus& completion_status, 119 mojom::URLResponseHeadPtr response_head, 120 const std::string& content, 121 ResponseMatchFlags flags = kMatchDefault); 122 123 // Simpler version of above for the common case of success or error page. 124 bool SimulateResponseForPendingRequest( 125 const std::string& url, 126 const std::string& content, 127 net::HttpStatusCode status = net::HTTP_OK, 128 ResponseMatchFlags flags = kMatchDefault); 129 130 // Sends a response for the given request |request|. 131 // 132 // Differently from its variant above, this method does not remove |request| 133 // from |pending_requests_|. 134 // 135 // This method is useful to process requests at a given pre-defined order. 136 void SimulateResponseWithoutRemovingFromPendingList( 137 PendingRequest* request, 138 mojom::URLResponseHeadPtr head, 139 std::string content, 140 const URLLoaderCompletionStatus& status); 141 142 // Simpler version of the method above. 143 void SimulateResponseWithoutRemovingFromPendingList(PendingRequest* request, 144 std::string content); 145 146 // mojom::URLLoaderFactory implementation. 147 void CreateLoaderAndStart(mojo::PendingReceiver<mojom::URLLoader> receiver, 148 int32_t routing_id, 149 int32_t request_id, 150 uint32_t options, 151 const ResourceRequest& url_request, 152 mojo::PendingRemote<mojom::URLLoaderClient> client, 153 const net::MutableNetworkTrafficAnnotationTag& 154 traffic_annotation) override; 155 void Clone(mojo::PendingReceiver<mojom::URLLoaderFactory> receiver) override; 156 157 // Returns a 'safe' ref-counted weak wrapper around this TestURLLoaderFactory 158 // instance. 159 // 160 // Because this is a weak wrapper, it is possible for the underlying 161 // TestURLLoaderFactory instance to be destroyed while other code still holds 162 // a reference to it. 163 // 164 // The weak wrapper returned by this method is guaranteed to have had 165 // Detach() called before this is destructed, so that any future calls become 166 // no-ops, rather than a crash. 167 scoped_refptr<network::WeakWrapperSharedURLLoaderFactory> 168 GetSafeWeakWrapper(); 169 170 private: 171 bool CreateLoaderAndStartInternal(const GURL& url, 172 mojom::URLLoaderClient* client); 173 174 static void SimulateResponse(mojom::URLLoaderClient* client, 175 Redirects redirects, 176 mojom::URLResponseHeadPtr head, 177 std::string content, 178 URLLoaderCompletionStatus status, 179 ResponseProduceFlags response_flags); 180 181 struct Response { 182 Response(); 183 ~Response(); 184 Response(Response&&); 185 Response& operator=(Response&&); 186 GURL url; 187 Redirects redirects; 188 mojom::URLResponseHeadPtr head; 189 std::string content; 190 URLLoaderCompletionStatus status; 191 ResponseProduceFlags flags; 192 }; 193 std::map<GURL, Response> responses_; 194 195 std::vector<PendingRequest> pending_requests_; 196 197 scoped_refptr<network::WeakWrapperSharedURLLoaderFactory> weak_wrapper_; 198 199 Interceptor interceptor_; 200 mojo::ReceiverSet<network::mojom::URLLoaderFactory> receivers_; 201 202 DISALLOW_COPY_AND_ASSIGN(TestURLLoaderFactory); 203 }; 204 205 } // namespace network 206 207 #endif // SERVICES_NETWORK_TEST_TEST_URL_LOADER_FACTORY_H_ 208