Fix breakages in https://codereview.chromium.org/1155713003/
[chromium-blink-merge.git] / ios / web / net / request_tracker_impl_unittest.mm
blob893f9abf92cbf798de47be4f3e138892a75f1231
1 // Copyright 2012 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.
5 #include "ios/web/net/request_tracker_impl.h"
7 #include "base/logging.h"
8 #include "base/mac/scoped_nsobject.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "ios/web/public/cert_policy.h"
13 #include "ios/web/public/certificate_policy_cache.h"
14 #include "ios/web/public/ssl_status.h"
15 #include "ios/web/public/test/test_browser_state.h"
16 #include "ios/web/public/test/test_web_thread.h"
17 #include "net/cert/x509_certificate.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/url_request/url_request.h"
20 #include "net/url_request/url_request_context.h"
21 #include "net/url_request/url_request_job_factory.h"
22 #include "net/url_request/url_request_job_factory_impl.h"
23 #include "net/url_request/url_request_test_job.h"
24 #include "net/url_request/url_request_test_util.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "testing/gtest_mac.h"
27 #include "testing/platform_test.h"
28 #import "third_party/ocmock/OCMock/OCMock.h"
29 #include "third_party/ocmock/gtest_support.h"
31 @interface RequestTrackerNotificationReceiverTest
32     : NSObject<CRWRequestTrackerDelegate> {
33  @public
34   float value_;
35   float max_;
36  @private
37   base::scoped_nsobject<NSString> error_;
38   scoped_refptr<net::HttpResponseHeaders> headers_;
41 - (NSString*)error;
42 - (net::HttpResponseHeaders*)headers;
43 @end
45 @implementation RequestTrackerNotificationReceiverTest
47 - (id)init {
48   self = [super init];
49   if (self) {
50     value_ = 0.0f;
51     max_ = 0.0f;
52   }
53   return self;
56 - (BOOL)isForStaticFileRequests {
57   return NO;
60 - (void)updatedProgress:(float)progress {
61   if (progress > 0.0f) {
62     if (progress < value_) {
63       error_.reset(
64           [[NSString stringWithFormat:
65               @"going down from %f to %f", value_, progress] retain]);
66     }
67     value_ = progress;
68   } else {
69     value_ = 0.0f;
70   }
71   if (value_ > max_) {
72     max_ = value_;
73   }
76 - (NSString*)error {
77   return error_;
80 - (void)handleResponseHeaders:(net::HttpResponseHeaders*)headers
81                    requestUrl:(const GURL&)requestUrl {
82   headers_ = headers;
85 - (net::HttpResponseHeaders*)headers {
86   return headers_.get();
89 - (void)updatedSSLStatus:(const web::SSLStatus&)sslStatus
90               forPageUrl:(const GURL&)url
91                 userInfo:(id)userInfo {
92   // Nothing. yet.
95 - (void)presentSSLError:(const net::SSLInfo&)info
96            forSSLStatus:(const web::SSLStatus&)status
97                   onUrl:(const GURL&)url
98             recoverable:(BOOL)recoverable
99                callback:(SSLErrorCallback)shouldContinue {
100   // Nothing, yet.
103 - (void)certificateUsed:(net::X509Certificate*)certificate
104                 forHost:(const std::string&)host
105                  status:(net::CertStatus)status {
106   // Nothing, yet.
109 - (void)clearCertificates {
110   // Nothing, yet.
113 - (void)handlePassKitObject:(NSData*)data {
114   // Nothing yet.
117 @end
119 namespace {
121 // Used and incremented each time a tabId is created.
122 int g_count = 0;
124 class RequestTrackerTest : public PlatformTest {
125  public:
126   RequestTrackerTest()
127       : loop_(base::MessageLoop::TYPE_IO),
128         ui_thread_(web::WebThread::UI, &loop_),
129         io_thread_(web::WebThread::IO, &loop_){};
131   ~RequestTrackerTest() override {}
133   void SetUp() override {
134     DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
135     request_group_id_.reset(
136         [[NSString stringWithFormat:@"test%d", g_count++] retain]);
138     receiver_.reset([[RequestTrackerNotificationReceiverTest alloc] init]);
139     tracker_ = web::RequestTrackerImpl::CreateTrackerForRequestGroupID(
140         request_group_id_,
141         &browser_state_,
142         browser_state_.GetRequestContext(),
143         receiver_);
144   }
146   void TearDown() override {
147     DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
148     tracker_->Close();
149   }
151   base::MessageLoop loop_;
152   web::TestWebThread ui_thread_;
153   web::TestWebThread io_thread_;
155   base::scoped_nsobject<RequestTrackerNotificationReceiverTest> receiver_;
156   scoped_refptr<web::RequestTrackerImpl> tracker_;
157   base::scoped_nsobject<NSString> request_group_id_;
158   web::TestBrowserState browser_state_;
159   ScopedVector<net::URLRequestContext> contexts_;
160   ScopedVector<net::URLRequest> requests_;
161   net::URLRequestJobFactoryImpl job_factory_;
163   GURL GetURL(size_t i) {
164     std::stringstream ss;
165     ss << "http://www/";
166     ss << i;
167     return GURL(ss.str());
168   }
170   GURL GetSecureURL(size_t i) {
171     std::stringstream ss;
172     ss << "https://www/";
173     ss << i;
174     return GURL(ss.str());
175   }
177   net::URLRequest* GetRequest(size_t i) {
178     return GetInternalRequest(i, false);
179   }
181   net::URLRequest* GetSecureRequest(size_t i) {
182     return GetInternalRequest(i, true);
183   }
185   NSString* WaitUntilLoop(bool (^condition)(void)) {
186     DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
187     base::Time maxDate = base::Time::Now() + base::TimeDelta::FromSeconds(10);
188     while (!condition()) {
189       if ([receiver_ error])
190         return [receiver_ error];
191       if (base::Time::Now() > maxDate)
192         return @"Time is up, too slow to go";
193       loop_.RunUntilIdle();
194       base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
195     }
196     return nil;
197   }
199   NSString* CheckActive() {
200     NSString* message = WaitUntilLoop(^{
201       return (receiver_.get()->value_ > 0.0f);
202     });
204     if (!message && (receiver_.get()->max_ == 0.0f))
205       message = @"Max should be greater than 0.0";
206     return message;
207   }
209   void TrimRequest(NSString* tab_id, const GURL& url) {
210     DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
211     receiver_.get()->value_ = 0.0f;
212     receiver_.get()->max_ = 0.0f;
213     tracker_->StartPageLoad(url, nil);
214   }
216   void EndPage(NSString* tab_id, const GURL& url) {
217     DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
218     tracker_->FinishPageLoad(url, false);
219     receiver_.get()->value_ = 0.0f;
220     receiver_.get()->max_ = 0.0f;
221     loop_.RunUntilIdle();
222   }
224   net::TestJobInterceptor* AddInterceptorToRequest(size_t i) {
225     // |interceptor| will be deleted from |job_factory_|'s destructor.
226     net::TestJobInterceptor* protocol_handler = new net::TestJobInterceptor();
227     job_factory_.SetProtocolHandler("http", protocol_handler);
228     contexts_[i]->set_job_factory(&job_factory_);
229     return protocol_handler;
230   }
232  private:
233   net::URLRequest* GetInternalRequest(size_t i, bool secure) {
234     GURL url;
235     if (secure)
236       url = GetSecureURL(requests_.size());
237     else
238       url = GetURL(requests_.size());
240     while (i >= requests_.size()) {
241       contexts_.push_back(new net::URLRequestContext());
242       requests_.push_back(contexts_[i]->CreateRequest(url,
243                                                       net::DEFAULT_PRIORITY,
244                                                       NULL).release());
246       if (secure) {
247         // Put a valid SSLInfo inside
248         net::HttpResponseInfo* response =
249             const_cast<net::HttpResponseInfo*>(&requests_[i]->response_info());
251         response->ssl_info.cert = new net::X509Certificate(
252             "subject", "issuer",
253             base::Time::Now() - base::TimeDelta::FromDays(2),
254             base::Time::Now() + base::TimeDelta::FromDays(2));
255         response->ssl_info.cert_status = 0;  // No errors.
256         response->ssl_info.security_bits = 128;
258         EXPECT_TRUE(requests_[i]->ssl_info().is_valid());
259       }
260     }
261     EXPECT_TRUE(!secure == !requests_[i]->url().SchemeIsCryptographic());
262     return requests_[i];
263   }
265   DISALLOW_COPY_AND_ASSIGN(RequestTrackerTest);
268 TEST_F(RequestTrackerTest, OnePage) {
269   // Start a request.
270   tracker_->StartRequest(GetRequest(0));
271   // Start page load.
272   TrimRequest(request_group_id_, GetURL(0));
273   EXPECT_NSEQ(nil, CheckActive());
275   // Stop the request.
276   tracker_->StopRequest(GetRequest(0));
277   EndPage(request_group_id_, GetURL(0));
280 TEST_F(RequestTrackerTest, OneSecurePage) {
281   net::URLRequest* request = GetSecureRequest(0);
282   GURL url = GetSecureURL(0);
284   // Start a page.
285   TrimRequest(request_group_id_, url);
287   // Start a request.
288   tracker_->StartRequest(request);
289   tracker_->CaptureReceivedBytes(request, 42);
290   EXPECT_NSEQ(nil, CheckActive());
292   // Stop the request.
293   tracker_->StopRequest(request);
295   EndPage(request_group_id_, url);
298 TEST_F(RequestTrackerTest, OnePageAndResources) {
299   // Start a page.
300   TrimRequest(request_group_id_, GetURL(0));
301   // Start two requests.
302   tracker_->StartRequest(GetRequest(0));
303   tracker_->StartRequest(GetRequest(1));
304   EXPECT_NSEQ(nil, CheckActive());
306   tracker_->StopRequest(GetRequest(0));
307   tracker_->StartRequest(GetRequest(2));
308   EXPECT_NSEQ(nil, CheckActive());
309   tracker_->StopRequest(GetRequest(1));
310   tracker_->StartRequest(GetRequest(3));
311   EXPECT_NSEQ(nil, CheckActive());
313   tracker_->StopRequest(GetRequest(2));
314   tracker_->StartRequest(GetRequest(4));
315   EXPECT_NSEQ(nil, CheckActive());
317   tracker_->StopRequest(GetRequest(3));
318   tracker_->StopRequest(GetRequest(4));
319   EndPage(request_group_id_, GetURL(0));
322 TEST_F(RequestTrackerTest, OnePageOneBigImage) {
323   // Start a page.
324   TrimRequest(request_group_id_, GetURL(0));
325   tracker_->StartRequest(GetRequest(0));
326   tracker_->StopRequest(GetRequest(0));
327   tracker_->StartRequest(GetRequest(1));
328   EXPECT_NSEQ(nil, CheckActive());
330   tracker_->CaptureReceivedBytes(GetRequest(1), 10);
331   tracker_->CaptureExpectedLength(GetRequest(1), 100);
332   tracker_->CaptureReceivedBytes(GetRequest(1), 10);
333   tracker_->CaptureReceivedBytes(GetRequest(1), 10);
334   tracker_->CaptureReceivedBytes(GetRequest(1), 10);
335   tracker_->CaptureReceivedBytes(GetRequest(1), 10);
336   EXPECT_NSEQ(nil, CheckActive());
338   tracker_->CaptureReceivedBytes(GetRequest(1), 10);
339   tracker_->CaptureReceivedBytes(GetRequest(1), 10);
340   tracker_->CaptureReceivedBytes(GetRequest(1), 10);
341   tracker_->CaptureReceivedBytes(GetRequest(1), 10);
342   tracker_->CaptureReceivedBytes(GetRequest(1), 10);
343   tracker_->StopRequest(GetRequest(1));
344   EndPage(request_group_id_, GetURL(0));
347 TEST_F(RequestTrackerTest, TwoPagesPostStart) {
348   tracker_->StartRequest(GetRequest(0));
350   TrimRequest(request_group_id_, GetURL(0));
351   EXPECT_NSEQ(nil, CheckActive());
352   tracker_->StartRequest(GetRequest(1));
353   tracker_->StartRequest(GetRequest(2));
354   EXPECT_NSEQ(nil, CheckActive());
356   tracker_->StopRequest(GetRequest(0));
357   tracker_->StopRequest(GetRequest(1));
358   tracker_->StopRequest(GetRequest(2));
359   EndPage(request_group_id_, GetURL(0));
361   tracker_->StartRequest(GetRequest(3));
363   TrimRequest(request_group_id_, GetURL(3));
364   EXPECT_NSEQ(nil, CheckActive());
366   tracker_->StopRequest(GetRequest(3));
367   EndPage(request_group_id_, GetURL(3));
370 TEST_F(RequestTrackerTest, TwoPagesPreStart) {
371   tracker_->StartRequest(GetRequest(0));
373   TrimRequest(request_group_id_, GetURL(0));
374   EXPECT_NSEQ(nil, CheckActive());
375   tracker_->StartRequest(GetRequest(1));
376   tracker_->StartRequest(GetRequest(2));
377   EXPECT_NSEQ(nil, CheckActive());
379   tracker_->StopRequest(GetRequest(0));
380   tracker_->StopRequest(GetRequest(1));
381   tracker_->StopRequest(GetRequest(2));
382   EndPage(request_group_id_, GetURL(0));
384   TrimRequest(request_group_id_, GetURL(3));
385   tracker_->StartRequest(GetRequest(3));
386   tracker_->StopRequest(GetRequest(3));
387   EndPage(request_group_id_, GetURL(3));
390 TEST_F(RequestTrackerTest, TwoPagesNoWait) {
391   tracker_->StartRequest(GetRequest(0));
393   TrimRequest(request_group_id_, GetURL(0));
394   EXPECT_NSEQ(nil, CheckActive());
395   tracker_->StartRequest(GetRequest(1));
396   tracker_->StartRequest(GetRequest(2));
397   EXPECT_NSEQ(nil, CheckActive());
399   tracker_->StopRequest(GetRequest(0));
400   tracker_->StopRequest(GetRequest(1));
401   tracker_->StopRequest(GetRequest(2));
402   EXPECT_NSEQ(nil, CheckActive());
404   TrimRequest(request_group_id_, GetURL(3));
405   tracker_->StartRequest(GetRequest(3));
406   EXPECT_NSEQ(nil, CheckActive());
408   tracker_->StopRequest(GetRequest(3));
409   EXPECT_NSEQ(nil, CheckActive());
411   EndPage(request_group_id_, GetURL(3));
414 TEST_F(RequestTrackerTest, CaptureHeaders) {
415   std::string headers =
416       "HTTP/1.1 200 OK\n"
417       "content-type: multipart/mixed; boundary=inner\n"
418       "content-disposition: attachment; filename=\"name.pdf\"\n"
419       "X-Auto-Login: Hello World\n\n";
420   for (size_t i = 0; i < headers.length(); i++) {
421     if (headers.data()[i] == '\n')
422       const_cast<char*>(headers.data())[i] = '\0';
423   }
424   net::URLRequest* request = GetRequest(0);
425   const_cast<net::HttpResponseInfo&>(request->response_info()).headers =
426       new net::HttpResponseHeaders(headers);
427   // |job| will be owned by |request| and released from its destructor.
428   net::URLRequestTestJob* job = new net::URLRequestTestJob(
429       request, request->context()->network_delegate(), headers, "", false);
430   AddInterceptorToRequest(0)->set_main_intercept_job(job);
431   request->Start();
433   tracker_->StartRequest(request);
434   tracker_->CaptureHeaders(request);
435   tracker_->StopRequest(request);
436   loop_.RunUntilIdle();
437   EXPECT_TRUE([receiver_ headers]->HasHeaderValue("X-Auto-Login",
438                                                   "Hello World"));
439   std::string mimeType;
440   EXPECT_TRUE([receiver_ headers]->GetMimeType(&mimeType));
441   EXPECT_EQ("multipart/mixed", mimeType);
442   EXPECT_TRUE([receiver_ headers]->HasHeaderValue(
443       "Content-Disposition", "attachment; filename=\"name.pdf\""));
446 // Do-nothing mock CertificatePolicyCache. Allows all certs for all hosts.
447 class MockCertificatePolicyCache : public web::CertificatePolicyCache {
448  public:
449   MockCertificatePolicyCache() {}
451   void AllowCertForHost(net::X509Certificate* cert,
452                         const std::string& host,
453                         net::CertStatus error) override {
454   }
456   web::CertPolicy::Judgment QueryPolicy(net::X509Certificate* cert,
457                                         const std::string& host,
458                                         net::CertStatus error) override {
459     return web::CertPolicy::Judgment::ALLOWED;
460   }
462   void ClearCertificatePolicies() override {
463   }
465  private:
466   ~MockCertificatePolicyCache() override {}
469 void TwoStartsSSLCallback(bool* called, bool ok) {
470   *called = true;
473 // crbug/386180
474 TEST_F(RequestTrackerTest, DISABLED_TwoStartsNoEstimate) {
475   net::X509Certificate* cert =
476       new net::X509Certificate("subject", "issuer", base::Time::Now(),
477                                base::Time::Max());
478   net::SSLInfo ssl_info;
479   ssl_info.cert = cert;
480   ssl_info.cert_status = net::CERT_STATUS_AUTHORITY_INVALID;
481   scoped_refptr<MockCertificatePolicyCache> cache;
482   tracker_->SetCertificatePolicyCacheForTest(cache.get());
483   TrimRequest(request_group_id_, GetSecureURL(0));
484   tracker_->StartRequest(GetSecureRequest(0));
485   tracker_->StartRequest(GetSecureRequest(1));
486   bool request_0_called = false;
487   bool request_1_called = false;
488   tracker_->OnSSLCertificateError(GetSecureRequest(0), ssl_info, true,
489                                   base::Bind(&TwoStartsSSLCallback,
490                                              &request_0_called));
491   tracker_->OnSSLCertificateError(GetSecureRequest(1), ssl_info, true,
492                                   base::Bind(&TwoStartsSSLCallback,
493                                              &request_1_called));
494   EXPECT_TRUE(request_0_called);
495   EXPECT_TRUE(request_1_called);
498 }  // namespace