OLD | NEW |
| (Empty) |
1 // Copyright 2017 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 #include "base/run_loop.h" | |
6 #include "content/public/common/browser_side_navigation_policy.h" | |
7 #include "content/public/test/browser_test.h" | |
8 #include "headless/public/devtools/domains/network.h" | |
9 #include "headless/public/devtools/domains/page.h" | |
10 #include "headless/public/headless_devtools_client.h" | |
11 #include "headless/public/util/expedited_dispatcher.h" | |
12 #include "headless/public/util/generic_url_request_job.h" | |
13 #include "headless/public/util/url_fetcher.h" | |
14 #include "headless/test/headless_browser_test.h" | |
15 #include "net/url_request/url_request_job_factory.h" | |
16 #include "testing/gmock/include/gmock/gmock.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include "url/gurl.h" | |
19 | |
20 using testing::ContainerEq; | |
21 | |
22 namespace headless { | |
23 | |
24 namespace { | |
25 // Keep in sync with X_DevTools_Request_Id defined in HTTPNames.json5. | |
26 const char kDevtoolsRequestId[] = "X-DevTools-Request-Id"; | |
27 } // namespace | |
28 | |
29 namespace { | |
30 class RequestIdCorrelationProtocolHandler | |
31 : public net::URLRequestJobFactory::ProtocolHandler { | |
32 public: | |
33 explicit RequestIdCorrelationProtocolHandler( | |
34 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner) | |
35 : test_delegate_(new TestDelegate(this)), | |
36 dispatcher_(new ExpeditedDispatcher(io_thread_task_runner)) {} | |
37 | |
38 ~RequestIdCorrelationProtocolHandler() override {} | |
39 | |
40 struct Response { | |
41 Response() {} | |
42 Response(const std::string& body, const std::string& mime_type) | |
43 : data("HTTP/1.1 200 OK\r\nContent-Type: " + mime_type + "\r\n\r\n" + | |
44 body) {} | |
45 | |
46 std::string data; | |
47 }; | |
48 | |
49 void InsertResponse(const std::string& url, const Response& response) { | |
50 response_map_[url] = response; | |
51 } | |
52 | |
53 const Response* GetResponse(const std::string& url) const { | |
54 std::map<std::string, Response>::const_iterator find_it = | |
55 response_map_.find(url); | |
56 if (find_it == response_map_.end()) | |
57 return nullptr; | |
58 return &find_it->second; | |
59 } | |
60 | |
61 class MockURLFetcher : public URLFetcher { | |
62 public: | |
63 explicit MockURLFetcher( | |
64 const RequestIdCorrelationProtocolHandler* protocol_handler) | |
65 : protocol_handler_(protocol_handler) {} | |
66 ~MockURLFetcher() override {} | |
67 | |
68 // URLFetcher implementation: | |
69 void StartFetch(const GURL& url, | |
70 const std::string& method, | |
71 const net::HttpRequestHeaders& request_headers, | |
72 const std::string& devtools_request_id, | |
73 ResultListener* result_listener) override { | |
74 const Response* response = protocol_handler_->GetResponse(url.spec()); | |
75 if (!response) | |
76 result_listener->OnFetchStartError(net::ERR_FILE_NOT_FOUND); | |
77 | |
78 // The header used for correlation should not be sent to the fetcher. | |
79 EXPECT_FALSE(request_headers.HasHeader(kDevtoolsRequestId)); | |
80 | |
81 result_listener->OnFetchCompleteExtractHeaders( | |
82 url, 200, response->data.c_str(), response->data.size()); | |
83 } | |
84 | |
85 private: | |
86 const RequestIdCorrelationProtocolHandler* protocol_handler_; | |
87 | |
88 DISALLOW_COPY_AND_ASSIGN(MockURLFetcher); | |
89 }; | |
90 | |
91 class TestDelegate : public GenericURLRequestJob::Delegate { | |
92 public: | |
93 explicit TestDelegate(RequestIdCorrelationProtocolHandler* protocol_handler) | |
94 : protocol_handler_(protocol_handler) {} | |
95 ~TestDelegate() override {} | |
96 | |
97 // GenericURLRequestJob::Delegate implementation: | |
98 bool BlockOrRewriteRequest( | |
99 const GURL& url, | |
100 const std::string& devtools_id, | |
101 const std::string& method, | |
102 const std::string& referrer, | |
103 GenericURLRequestJob::RewriteCallback callback) override { | |
104 protocol_handler_->url_to_devtools_id_[url.spec()] = devtools_id; | |
105 return false; | |
106 } | |
107 | |
108 const GenericURLRequestJob::HttpResponse* MaybeMatchResource( | |
109 const GURL& url, | |
110 const std::string& devtools_id, | |
111 const std::string& method, | |
112 const net::HttpRequestHeaders& request_headers) override { | |
113 return nullptr; | |
114 } | |
115 | |
116 void OnResourceLoadComplete(const GURL& final_url, | |
117 const std::string& devtools_id, | |
118 const std::string& mime_type, | |
119 int http_response_code) override {} | |
120 | |
121 private: | |
122 RequestIdCorrelationProtocolHandler* protocol_handler_; | |
123 | |
124 DISALLOW_COPY_AND_ASSIGN(TestDelegate); | |
125 }; | |
126 | |
127 // net::URLRequestJobFactory::ProtocolHandler implementation:: | |
128 net::URLRequestJob* MaybeCreateJob( | |
129 net::URLRequest* request, | |
130 net::NetworkDelegate* network_delegate) const override { | |
131 return new GenericURLRequestJob( | |
132 request, network_delegate, dispatcher_.get(), | |
133 base::MakeUnique<MockURLFetcher>(this), test_delegate_.get()); | |
134 } | |
135 | |
136 std::map<std::string, std::string> url_to_devtools_id_; | |
137 | |
138 private: | |
139 std::unique_ptr<TestDelegate> test_delegate_; | |
140 std::unique_ptr<ExpeditedDispatcher> dispatcher_; | |
141 std::map<std::string, Response> response_map_; | |
142 | |
143 DISALLOW_COPY_AND_ASSIGN(RequestIdCorrelationProtocolHandler); | |
144 }; | |
145 | |
146 const char* kIndexHtml = R"( | |
147 <html> | |
148 <head> | |
149 <link rel="stylesheet" type="text/css" href="style1.css"> | |
150 <link rel="stylesheet" type="text/css" href="style2.css"> | |
151 </head> | |
152 <body>Hello. | |
153 </body> | |
154 </html>)"; | |
155 | |
156 const char* kStyle1 = R"( | |
157 .border { | |
158 border: 1px solid #000; | |
159 })"; | |
160 | |
161 const char* kStyle2 = R"( | |
162 .border { | |
163 border: 2px solid #fff; | |
164 })"; | |
165 | |
166 } // namespace | |
167 | |
168 class ProtocolHandlerRequestIdCorrelationTest | |
169 : public HeadlessAsyncDevTooledBrowserTest, | |
170 public network::Observer, | |
171 public page::Observer { | |
172 public: | |
173 void RunDevTooledTest() override { | |
174 if (content::IsBrowserSideNavigationEnabled()) { | |
175 // TODO: get this working with PlzNavigate. | |
176 // See discussion on https://codereview.chromium.org/2695923010/ | |
177 FinishAsynchronousTest(); | |
178 return; | |
179 } | |
180 | |
181 EXPECT_TRUE(embedded_test_server()->Start()); | |
182 devtools_client_->GetPage()->AddObserver(this); | |
183 devtools_client_->GetPage()->Enable(); | |
184 | |
185 base::RunLoop run_loop; | |
186 devtools_client_->GetNetwork()->AddObserver(this); | |
187 devtools_client_->GetNetwork()->Enable(run_loop.QuitClosure()); | |
188 base::MessageLoop::ScopedNestableTaskAllower nest_loop( | |
189 base::MessageLoop::current()); | |
190 run_loop.Run(); | |
191 | |
192 devtools_client_->GetPage()->Navigate("http://foo.com/index.html"); | |
193 } | |
194 | |
195 ProtocolHandlerMap GetProtocolHandlers() override { | |
196 ProtocolHandlerMap protocol_handlers; | |
197 std::unique_ptr<RequestIdCorrelationProtocolHandler> http_handler( | |
198 new RequestIdCorrelationProtocolHandler(browser()->BrowserIOThread())); | |
199 http_handler_ = http_handler.get(); | |
200 http_handler_->InsertResponse("http://foo.com/index.html", | |
201 {kIndexHtml, "text/html"}); | |
202 http_handler_->InsertResponse("http://foo.com/style1.css", | |
203 {kStyle1, "text/css"}); | |
204 http_handler_->InsertResponse("http://foo.com/style2.css", | |
205 {kStyle2, "text/css"}); | |
206 protocol_handlers[url::kHttpScheme] = std::move(http_handler); | |
207 return protocol_handlers; | |
208 } | |
209 | |
210 // network::Observer implementation: | |
211 void OnRequestWillBeSent( | |
212 const network::RequestWillBeSentParams& params) override { | |
213 url_to_devtools_id_[params.GetRequest()->GetUrl()] = params.GetRequestId(); | |
214 EXPECT_FALSE(params.GetRequest()->GetHeaders()->HasKey(kDevtoolsRequestId)); | |
215 } | |
216 | |
217 // page::Observer implementation: | |
218 void OnLoadEventFired(const page::LoadEventFiredParams& params) override { | |
219 // Make sure that our protocol handler saw the same url : devtools ids as | |
220 // our OnRequestWillBeSent event listener did. | |
221 EXPECT_THAT(url_to_devtools_id_, | |
222 ContainerEq(http_handler_->url_to_devtools_id_)); | |
223 EXPECT_EQ(3u, url_to_devtools_id_.size()); | |
224 FinishAsynchronousTest(); | |
225 } | |
226 | |
227 private: | |
228 std::map<std::string, std::string> url_to_devtools_id_; | |
229 RequestIdCorrelationProtocolHandler* http_handler_; // NOT OWNED | |
230 }; | |
231 | |
232 HEADLESS_ASYNC_DEVTOOLED_TEST_F(ProtocolHandlerRequestIdCorrelationTest); | |
233 | |
234 } // namespace headless | |
OLD | NEW |