1 // Copyright (c) 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.
4 
5 #include "ppapi/tests/test_url_loader.h"
6 
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <string>
11 
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/c/ppb_file_io.h"
14 #include "ppapi/c/ppb_url_loader.h"
15 #include "ppapi/c/trusted/ppb_url_loader_trusted.h"
16 #include "ppapi/cpp/dev/url_util_dev.h"
17 #include "ppapi/cpp/file_io.h"
18 #include "ppapi/cpp/file_ref.h"
19 #include "ppapi/cpp/file_system.h"
20 #include "ppapi/cpp/instance.h"
21 #include "ppapi/cpp/module.h"
22 #include "ppapi/cpp/private/file_io_private.h"
23 #include "ppapi/cpp/url_loader.h"
24 #include "ppapi/cpp/url_request_info.h"
25 #include "ppapi/cpp/url_response_info.h"
26 #include "ppapi/tests/test_utils.h"
27 #include "ppapi/tests/testing_instance.h"
28 
29 REGISTER_TEST_CASE(URLLoader);
30 
31 namespace {
32 
WriteEntireBuffer(PP_Instance instance,pp::FileIO * file_io,int32_t offset,const std::string & data,CallbackType callback_type)33 int32_t WriteEntireBuffer(PP_Instance instance,
34                           pp::FileIO* file_io,
35                           int32_t offset,
36                           const std::string& data,
37                           CallbackType callback_type) {
38   TestCompletionCallback callback(instance, callback_type);
39   int32_t write_offset = offset;
40   const char* buf = data.c_str();
41   int32_t size = static_cast<int32_t>(data.size());
42 
43   while (write_offset < offset + size) {
44     callback.WaitForResult(file_io->Write(write_offset,
45                                           &buf[write_offset - offset],
46                                           size - write_offset + offset,
47                                           callback.GetCallback()));
48     if (callback.result() < 0)
49       return callback.result();
50     if (callback.result() == 0)
51       return PP_ERROR_FAILED;
52     write_offset += callback.result();
53   }
54 
55   return PP_OK;
56 }
57 
58 }  // namespace
59 
TestURLLoader(TestingInstance * instance)60 TestURLLoader::TestURLLoader(TestingInstance* instance)
61     : TestCase(instance),
62       file_io_private_interface_(NULL),
63       url_loader_trusted_interface_(NULL) {
64 }
65 
Init()66 bool TestURLLoader::Init() {
67   if (!CheckTestingInterface()) {
68     instance_->AppendError("Testing interface not available");
69     return false;
70   }
71 
72   const PPB_FileIO* file_io_interface = static_cast<const PPB_FileIO*>(
73       pp::Module::Get()->GetBrowserInterface(PPB_FILEIO_INTERFACE));
74   if (!file_io_interface)
75     instance_->AppendError("FileIO interface not available");
76 
77   file_io_private_interface_ = static_cast<const PPB_FileIO_Private*>(
78       pp::Module::Get()->GetBrowserInterface(PPB_FILEIO_PRIVATE_INTERFACE));
79   if (!file_io_private_interface_)
80     instance_->AppendError("FileIO_Private interface not available");
81   url_loader_trusted_interface_ = static_cast<const PPB_URLLoaderTrusted*>(
82       pp::Module::Get()->GetBrowserInterface(PPB_URLLOADERTRUSTED_INTERFACE));
83   if (!testing_interface_->IsOutOfProcess()) {
84     // Trusted interfaces are not supported under NaCl.
85 #if !(defined __native_client__)
86     if (!url_loader_trusted_interface_)
87       instance_->AppendError("URLLoaderTrusted interface not available");
88 #else
89     if (url_loader_trusted_interface_)
90       instance_->AppendError("URLLoaderTrusted interface is supported by NaCl");
91 #endif
92   }
93   return EnsureRunningOverHTTP();
94 }
95 
96 /*
97  * The test order is important here, as running tests out of order may cause
98  * test timeout.
99  *
100  * Here is the environment:
101  *
102  * 1. net::EmbeddedTestServer only accepts one open connection at the time.
103  * 2. HTTP socket pool keeps sockets open for several seconds after last use
104  * (hoping that there will be another request that could reuse the connection).
105  * 3. HTTP socket pool is separated by host/port and privacy mode (which is
106  * based on cookies set/get permissions). So, connections to 127.0.0.1,
107  * localhost and localhost in privacy mode cannot reuse existing socket and will
108  * try to open another connection.
109  *
110  * Here is the problem:
111  *
112  * Original test order was repeatedly accessing 127.0.0.1, localhost and
113  * localhost in privacy mode, causing new sockets to open and try to connect to
114  * testserver, which they couldn't until previous connection is closed by socket
115  * pool idle socket timeout (10 seconds).
116  *
117  * Because of this the test run was taking around 45 seconds, and test was
118  * reported as 'timed out' by trybot.
119  *
120  * Re-ordering of tests provides more sequential access to 127.0.0.1, localhost
121  * and localhost in privacy mode. It decreases the number of times when socket
122  * pool doesn't have existing connection to host and has to wait, therefore
123  * reducing total test time and ensuring its completion under 30 seconds.
124  */
RunTests(const std::string & filter)125 void TestURLLoader::RunTests(const std::string& filter) {
126   // These tests connect to 127.0.0.1:
127   RUN_CALLBACK_TEST(TestURLLoader, BasicGET, filter);
128   RUN_CALLBACK_TEST(TestURLLoader, BasicPOST, filter);
129   RUN_CALLBACK_TEST(TestURLLoader, BasicFilePOST, filter);
130   RUN_CALLBACK_TEST(TestURLLoader, BasicFileRangePOST, filter);
131   RUN_CALLBACK_TEST(TestURLLoader, CompoundBodyPOST, filter);
132   RUN_CALLBACK_TEST(TestURLLoader, EmptyDataPOST, filter);
133   RUN_CALLBACK_TEST(TestURLLoader, BinaryDataPOST, filter);
134   RUN_CALLBACK_TEST(TestURLLoader, CustomRequestHeader, filter);
135   RUN_CALLBACK_TEST(TestURLLoader, FailsBogusContentLength, filter);
136   RUN_CALLBACK_TEST(TestURLLoader, StreamToFile, filter);
137   RUN_CALLBACK_TEST(TestURLLoader, UntrustedJavascriptURLRestriction, filter);
138   RUN_CALLBACK_TEST(TestURLLoader, TrustedJavascriptURLRestriction, filter);
139   RUN_CALLBACK_TEST(TestURLLoader, UntrustedHttpRequests, filter);
140   RUN_CALLBACK_TEST(TestURLLoader, TrustedHttpRequests, filter);
141   RUN_CALLBACK_TEST(TestURLLoader, FollowURLRedirect, filter);
142   RUN_CALLBACK_TEST(TestURLLoader, AuditURLRedirect, filter);
143   RUN_CALLBACK_TEST(TestURLLoader, RestrictURLRedirectCommon, filter);
144   RUN_CALLBACK_TEST(TestURLLoader, RestrictURLRedirectEnabled, filter);
145   RUN_CALLBACK_TEST(TestURLLoader, RestrictURLRedirectDisabled, filter);
146   RUN_CALLBACK_TEST(TestURLLoader, AbortCalls, filter);
147   RUN_CALLBACK_TEST(TestURLLoader, UntendedLoad, filter);
148   RUN_CALLBACK_TEST(TestURLLoader, PrefetchBufferThreshold, filter);
149   RUN_CALLBACK_TEST(TestURLLoader, XRequestedWithHeader, filter);
150   // These tests connect to localhost with privacy mode enabled:
151   RUN_CALLBACK_TEST(TestURLLoader, UntrustedSameOriginRestriction, filter);
152   RUN_CALLBACK_TEST(TestURLLoader, UntrustedCrossOriginRequest, filter);
153   RUN_CALLBACK_TEST(TestURLLoader, UntrustedCorbEligibleRequest, filter);
154   // These tests connect to localhost with privacy mode disabled:
155   RUN_CALLBACK_TEST(TestURLLoader, TrustedSameOriginRestriction, filter);
156   RUN_CALLBACK_TEST(TestURLLoader, TrustedCrossOriginRequest, filter);
157   RUN_CALLBACK_TEST(TestURLLoader, TrustedCorbEligibleRequest, filter);
158 }
159 
ReadEntireFile(pp::FileIO * file_io,std::string * data)160 std::string TestURLLoader::ReadEntireFile(pp::FileIO* file_io,
161                                           std::string* data) {
162   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
163   char buf[256];
164   int64_t offset = 0;
165 
166   for (;;) {
167     callback.WaitForResult(file_io->Read(offset, buf, sizeof(buf),
168                            callback.GetCallback()));
169     if (callback.result() < 0)
170       return ReportError("FileIO::Read", callback.result());
171     if (callback.result() == 0)
172       break;
173     offset += callback.result();
174     data->append(buf, callback.result());
175   }
176 
177   PASS();
178 }
179 
ReadEntireResponseBody(pp::URLLoader * loader,std::string * body)180 std::string TestURLLoader::ReadEntireResponseBody(pp::URLLoader* loader,
181                                                   std::string* body) {
182   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
183   char buf[2];  // Small so that multiple reads are needed.
184 
185   for (;;) {
186     callback.WaitForResult(
187         loader->ReadResponseBody(buf, sizeof(buf), callback.GetCallback()));
188     if (callback.result() < 0)
189       return ReportError("URLLoader::ReadResponseBody", callback.result());
190     if (callback.result() == 0)
191       break;
192     body->append(buf, callback.result());
193   }
194 
195   PASS();
196 }
197 
LoadAndCompareBody(const pp::URLRequestInfo & request,const std::string & expected_body)198 std::string TestURLLoader::LoadAndCompareBody(
199     const pp::URLRequestInfo& request,
200     const std::string& expected_body) {
201   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
202 
203   pp::URLLoader loader(instance_);
204   callback.WaitForResult(loader.Open(request, callback.GetCallback()));
205   CHECK_CALLBACK_BEHAVIOR(callback);
206   ASSERT_EQ(PP_OK, callback.result());
207 
208   pp::URLResponseInfo response_info(loader.GetResponseInfo());
209   if (response_info.is_null())
210     return "URLLoader::GetResponseInfo returned null";
211   int32_t status_code = response_info.GetStatusCode();
212   if (status_code != 200)
213     return "Unexpected HTTP status code";
214 
215   std::string body;
216   std::string error = ReadEntireResponseBody(&loader, &body);
217   if (!error.empty())
218     return error;
219 
220   if (body.size() != expected_body.size())
221     return "URLLoader::ReadResponseBody returned unexpected content length";
222   if (body != expected_body)
223     return "URLLoader::ReadResponseBody returned unexpected content";
224 
225   PASS();
226 }
227 
LoadAndFail(const pp::URLRequestInfo & request)228 std::string TestURLLoader::LoadAndFail(const pp::URLRequestInfo& request) {
229   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
230 
231   pp::URLLoader loader(instance_);
232   callback.WaitForResult(loader.Open(request, callback.GetCallback()));
233   CHECK_CALLBACK_BEHAVIOR(callback);
234   ASSERT_EQ(PP_ERROR_FAILED, callback.result());
235 
236   PASS();
237 }
238 
OpenFileSystem(pp::FileSystem * file_system,std::string * message)239 int32_t TestURLLoader::OpenFileSystem(pp::FileSystem* file_system,
240                                       std::string* message) {
241   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
242   callback.WaitForResult(file_system->Open(1024, callback.GetCallback()));
243   if (callback.failed()) {
244     message->assign(callback.errors());
245     return callback.result();
246   }
247   if (callback.result() != PP_OK) {
248     message->assign("FileSystem::Open");
249     return callback.result();
250   }
251   return callback.result();
252 }
253 
PrepareFileForPost(const pp::FileRef & file_ref,const std::string & data,std::string * message)254 int32_t TestURLLoader::PrepareFileForPost(
255       const pp::FileRef& file_ref,
256       const std::string& data,
257       std::string* message) {
258   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
259   pp::FileIO file_io(instance_);
260   callback.WaitForResult(file_io.Open(file_ref,
261                                       PP_FILEOPENFLAG_CREATE |
262                                       PP_FILEOPENFLAG_TRUNCATE |
263                                       PP_FILEOPENFLAG_WRITE,
264                                       callback.GetCallback()));
265   if (callback.failed()) {
266     message->assign(callback.errors());
267     return callback.result();
268   }
269   if (callback.result() != PP_OK) {
270     message->assign("FileIO::Open failed.");
271     return callback.result();
272   }
273 
274   int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, data,
275                                  callback_type());
276   if (rv != PP_OK) {
277     message->assign("FileIO::Write failed.");
278     return rv;
279   }
280 
281   return rv;
282 }
283 
GetReachableAbsoluteURL(const std::string & file_name)284 std::string TestURLLoader::GetReachableAbsoluteURL(
285     const std::string& file_name) {
286   // Get the absolute page URL and replace the test case file name
287   // with the given one.
288   pp::Var document_url(
289       pp::PASS_REF,
290       testing_interface_->GetDocumentURL(instance_->pp_instance(),
291                                          NULL));
292   std::string url(document_url.AsString());
293   std::string old_name("test_case.html");
294   size_t index = url.find(old_name);
295   ASSERT_NE(index, std::string::npos);
296   url.replace(index, old_name.length(), file_name);
297   return url;
298 }
299 
GetReachableCrossOriginURL(const std::string & file_name)300 std::string TestURLLoader::GetReachableCrossOriginURL(
301     const std::string& file_name) {
302   // Get an absolute URL and use it to construct a URL that will be
303   // considered cross-origin by the CORS access control code, and yet be
304   // reachable by the test server.
305   std::string url = GetReachableAbsoluteURL(file_name);
306   // Replace '127.0.0.1' with 'localhost'.
307   std::string host("127.0.0.1");
308   size_t index = url.find(host);
309   ASSERT_NE(index, std::string::npos);
310   url.replace(index, host.length(), "localhost");
311   return url;
312 }
313 
OpenUntrusted(const std::string & method,const std::string & header)314 int32_t TestURLLoader::OpenUntrusted(const std::string& method,
315                                      const std::string& header) {
316   pp::URLRequestInfo request(instance_);
317   request.SetURL("/echo");
318   request.SetMethod(method);
319   request.SetHeaders(header);
320 
321   return OpenUntrusted(request, NULL);
322 }
323 
OpenTrusted(const std::string & method,const std::string & header)324 int32_t TestURLLoader::OpenTrusted(const std::string& method,
325                                    const std::string& header) {
326   pp::URLRequestInfo request(instance_);
327   request.SetURL("/echo");
328   request.SetMethod(method);
329   request.SetHeaders(header);
330 
331   return OpenTrusted(request, NULL);
332 }
333 
OpenUntrusted(const pp::URLRequestInfo & request,std::string * response_body)334 int32_t TestURLLoader::OpenUntrusted(const pp::URLRequestInfo& request,
335                                      std::string* response_body) {
336   return Open(request, false, response_body);
337 }
338 
OpenTrusted(const pp::URLRequestInfo & request,std::string * response_body)339 int32_t TestURLLoader::OpenTrusted(const pp::URLRequestInfo& request,
340                                    std::string* response_body) {
341   return Open(request, true, response_body);
342 }
343 
Open(const pp::URLRequestInfo & request,bool trusted,std::string * response_body)344 int32_t TestURLLoader::Open(const pp::URLRequestInfo& request,
345                             bool trusted,
346                             std::string* response_body) {
347   pp::URLLoader loader(instance_);
348   if (trusted)
349     url_loader_trusted_interface_->GrantUniversalAccess(loader.pp_resource());
350 
351   return OpenURLRequest(instance_->pp_instance(), &loader, request,
352                         callback_type(), response_body);
353 }
354 
TestBasicGET()355 std::string TestURLLoader::TestBasicGET() {
356   pp::URLRequestInfo request(instance_);
357   request.SetURL("test_url_loader_data/hello.txt");
358   return LoadAndCompareBody(request, "hello\n");
359 }
360 
TestBasicPOST()361 std::string TestURLLoader::TestBasicPOST() {
362   pp::URLRequestInfo request(instance_);
363   request.SetURL("/echo");
364   request.SetMethod("POST");
365   std::string postdata("postdata");
366   request.AppendDataToBody(postdata.data(),
367                            static_cast<uint32_t>(postdata.length()));
368   return LoadAndCompareBody(request, postdata);
369 }
370 
TestBasicFilePOST()371 std::string TestURLLoader::TestBasicFilePOST() {
372   std::string message;
373 
374   pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
375   int32_t rv = OpenFileSystem(&file_system, &message);
376   if (rv != PP_OK)
377     return ReportError(message.c_str(), rv);
378 
379   pp::FileRef file_ref(file_system, "/file_post_test");
380   std::string postdata("postdata");
381   rv = PrepareFileForPost(file_ref, postdata, &message);
382   if (rv != PP_OK)
383     return ReportError(message.c_str(), rv);
384 
385   pp::URLRequestInfo request(instance_);
386   request.SetURL("/echo");
387   request.SetMethod("POST");
388   request.AppendFileToBody(file_ref, 0);
389   return LoadAndCompareBody(request, postdata);
390 }
391 
TestBasicFileRangePOST()392 std::string TestURLLoader::TestBasicFileRangePOST() {
393   std::string message;
394 
395   pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
396   int32_t rv = OpenFileSystem(&file_system, &message);
397   if (rv != PP_OK)
398     return ReportError(message.c_str(), rv);
399 
400   pp::FileRef file_ref(file_system, "/file_range_post_test");
401   std::string postdata("postdatapostdata");
402   rv = PrepareFileForPost(file_ref, postdata, &message);
403   if (rv != PP_OK)
404     return ReportError(message.c_str(), rv);
405 
406   pp::URLRequestInfo request(instance_);
407   request.SetURL("/echo");
408   request.SetMethod("POST");
409   request.AppendFileRangeToBody(file_ref, 4, 12, 0);
410   return LoadAndCompareBody(request, postdata.substr(4, 12));
411 }
412 
TestCompoundBodyPOST()413 std::string TestURLLoader::TestCompoundBodyPOST() {
414   pp::URLRequestInfo request(instance_);
415   request.SetURL("/echo");
416   request.SetMethod("POST");
417   std::string postdata1("post");
418   request.AppendDataToBody(postdata1.data(),
419                            static_cast<uint32_t>(postdata1.length()));
420   std::string postdata2("data");
421   request.AppendDataToBody(postdata2.data(),
422                            static_cast<uint32_t>(postdata2.length()));
423   return LoadAndCompareBody(request, postdata1 + postdata2);
424 }
425 
TestEmptyDataPOST()426 std::string TestURLLoader::TestEmptyDataPOST() {
427   pp::URLRequestInfo request(instance_);
428   request.SetURL("/echo");
429   request.SetMethod("POST");
430   request.AppendDataToBody("", 0);
431   return LoadAndCompareBody(request, std::string());
432 }
433 
TestBinaryDataPOST()434 std::string TestURLLoader::TestBinaryDataPOST() {
435   pp::URLRequestInfo request(instance_);
436   request.SetURL("/echo");
437   request.SetMethod("POST");
438   const char postdata_chars[] =
439       "\x00\x01\x02\x03\x04\x05postdata\xfa\xfb\xfc\xfd\xfe\xff";
440   std::string postdata(postdata_chars,
441                        sizeof(postdata_chars) / sizeof(postdata_chars[0]));
442   request.AppendDataToBody(postdata.data(),
443                            static_cast<uint32_t>(postdata.length()));
444   return LoadAndCompareBody(request, postdata);
445 }
446 
TestCustomRequestHeader()447 std::string TestURLLoader::TestCustomRequestHeader() {
448   pp::URLRequestInfo request(instance_);
449   request.SetURL("/echoheader?Foo");
450   request.SetHeaders("Foo: 1");
451   return LoadAndCompareBody(request, "1");
452 }
453 
TestFailsBogusContentLength()454 std::string TestURLLoader::TestFailsBogusContentLength() {
455   pp::URLRequestInfo request(instance_);
456   request.SetURL("/echo");
457   request.SetMethod("POST");
458   request.SetHeaders("Content-Length: 400");
459   std::string postdata("postdata");
460   request.AppendDataToBody(postdata.data(),
461                            static_cast<uint32_t>(postdata.length()));
462 
463   int32_t rv;
464   rv = OpenUntrusted(request, NULL);
465   if (rv != PP_ERROR_NOACCESS)
466     return ReportError(
467         "Untrusted request with bogus Content-Length restriction", rv);
468 
469   PASS();
470 }
471 
TestStreamToFile()472 std::string TestURLLoader::TestStreamToFile() {
473   pp::URLRequestInfo request(instance_);
474   request.SetURL("test_url_loader_data/hello.txt");
475   ASSERT_FALSE(request.SetStreamToFile(true));
476 
477   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
478 
479   pp::URLLoader loader(instance_);
480   callback.WaitForResult(loader.Open(request, callback.GetCallback()));
481   CHECK_CALLBACK_BEHAVIOR(callback);
482   ASSERT_EQ(PP_OK, callback.result());
483 
484   pp::URLResponseInfo response_info(loader.GetResponseInfo());
485   if (response_info.is_null())
486     return "URLLoader::GetResponseInfo returned null";
487   int32_t status_code = response_info.GetStatusCode();
488   if (status_code != 200)
489     return "Unexpected HTTP status code";
490 
491   pp::FileRef body(response_info.GetBodyAsFileRef());
492   ASSERT_TRUE(body.is_null());
493 
494   callback.WaitForResult(loader.FinishStreamingToFile(callback.GetCallback()));
495   CHECK_CALLBACK_BEHAVIOR(callback);
496   ASSERT_EQ(PP_ERROR_NOTSUPPORTED, callback.result());
497 
498   PASS();
499 }
500 
501 // Untrusted, unintended cross-origin requests should fail.
TestUntrustedSameOriginRestriction()502 std::string TestURLLoader::TestUntrustedSameOriginRestriction() {
503   pp::URLRequestInfo request(instance_);
504   std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html");
505   request.SetURL(cross_origin_url);
506 
507   int32_t rv = OpenUntrusted(request, NULL);
508   if (rv != PP_ERROR_NOACCESS)
509     return ReportError(
510         "Untrusted, unintended cross-origin request restriction", rv);
511 
512   PASS();
513 }
514 
515 // Trusted, unintended cross-origin requests should succeed.
TestTrustedSameOriginRestriction()516 std::string TestURLLoader::TestTrustedSameOriginRestriction() {
517   pp::URLRequestInfo request(instance_);
518   std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html");
519   request.SetURL(cross_origin_url);
520 
521   int32_t rv = OpenTrusted(request, NULL);
522   if (rv != PP_OK)
523     return ReportError("Trusted cross-origin request failed", rv);
524 
525   PASS();
526 }
527 
528 // Untrusted, intended cross-origin requests should use CORS and succeed.
TestUntrustedCrossOriginRequest()529 std::string TestURLLoader::TestUntrustedCrossOriginRequest() {
530   pp::URLRequestInfo request(instance_);
531   std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html");
532   request.SetURL(cross_origin_url);
533   request.SetAllowCrossOriginRequests(true);
534 
535   int32_t rv = OpenUntrusted(request, NULL);
536   if (rv != PP_OK)
537     return ReportError(
538         "Untrusted, intended cross-origin request failed", rv);
539 
540   PASS();
541 }
542 
543 // Trusted, intended cross-origin requests should use CORS and succeed.
TestTrustedCrossOriginRequest()544 std::string TestURLLoader::TestTrustedCrossOriginRequest() {
545   pp::URLRequestInfo request(instance_);
546   std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html");
547   request.SetURL(cross_origin_url);
548   request.SetAllowCrossOriginRequests(true);
549 
550   int32_t rv = OpenTrusted(request, NULL);
551   if (rv != PP_OK)
552     return ReportError("Trusted cross-origin request failed", rv);
553 
554   PASS();
555 }
556 
557 // CORB (Cross-Origin Read Blocking) should apply to plugins without universal
558 // access.  This test is very similar to TestUntrustedSameOriginRestriction, but
559 // explicitly uses a CORB-eligible response (test/json + nosniff).
TestUntrustedCorbEligibleRequest()560 std::string TestURLLoader::TestUntrustedCorbEligibleRequest() {
561   // It is important to use a CORB-eligible response here: text/json + nosniff.
562   std::string cross_origin_url =
563       GetReachableCrossOriginURL("corb_eligible_resource.json");
564 
565   pp::URLRequestInfo request(instance_);
566   request.SetURL(cross_origin_url);
567   request.SetAllowCrossOriginRequests(true);
568 
569   std::string response_body;
570   int32_t rv = OpenUntrusted(request, &response_body);
571 
572   // Main verification - the response should be blocked.  Ideally the blocking
573   // should be done before the data leaves the browser and/or network-service
574   // process (the test doesn't verify this though).
575   if (rv != PP_ERROR_NOACCESS) {
576     return ReportError("Untrusted Javascript URL request restriction failed",
577                        rv);
578   }
579   ASSERT_EQ("", response_body);
580   PASS();
581 }
582 
583 // CORB (Cross-Origin Read Blocking) shouldn't apply to plugins with universal
584 // access (see PepperURLLoaderHost::has_universal_access_) - such plugins may
585 // have their own CORS-like mechanisms - e.g. crossdomain.xml in Flash).
586 // This test is quite similar to TestTrustedSameOriginRestriction, but it
587 // explicitly uses a CORB-eligible response (test/json + nosniff) and also
588 // explicitly verifies that the response body was not blocked.
TestTrustedCorbEligibleRequest()589 std::string TestURLLoader::TestTrustedCorbEligibleRequest() {
590   // It is important to use a CORB-eligible response here: text/json + nosniff.
591   std::string cross_origin_url =
592       GetReachableCrossOriginURL("corb_eligible_resource.json");
593 
594   pp::URLRequestInfo request(instance_);
595   request.SetURL(cross_origin_url);
596   request.SetAllowCrossOriginRequests(true);
597 
598   std::string response_body;
599   int32_t rv = OpenTrusted(request, &response_body);
600   if (rv != PP_OK)
601     return ReportError("Trusted CORB-eligible request failed", rv);
602 
603   // Main verification - if CORB blocked the response, then |response_body|
604   // would be empty.
605   ASSERT_EQ("{ \"foo\": \"bar\" }\n", response_body);
606   PASS();
607 }
608 
609 // Untrusted Javascript URLs requests should fail.
TestUntrustedJavascriptURLRestriction()610 std::string TestURLLoader::TestUntrustedJavascriptURLRestriction() {
611   pp::URLRequestInfo request(instance_);
612   request.SetURL("javascript:foo = bar");
613 
614   int32_t rv = OpenUntrusted(request, NULL);
615   if (rv != PP_ERROR_NOACCESS)
616     return ReportError(
617         "Untrusted Javascript URL request restriction failed", rv);
618 
619   PASS();
620 }
621 
622 // Trusted Javascript URLs requests should succeed.
TestTrustedJavascriptURLRestriction()623 std::string TestURLLoader::TestTrustedJavascriptURLRestriction() {
624   pp::URLRequestInfo request(instance_);
625   request.SetURL("javascript:foo = bar");
626 
627   int32_t rv = OpenTrusted(request, NULL);
628   if (rv == PP_ERROR_NOACCESS)
629   return ReportError(
630       "Trusted Javascript URL request", rv);
631 
632   PASS();
633 }
634 
TestUntrustedHttpRequests()635 std::string TestURLLoader::TestUntrustedHttpRequests() {
636   // HTTP methods are restricted only for untrusted loaders. Forbidden
637   // methods are CONNECT, TRACE, and TRACK, and any string that is not a
638   // valid token (containing special characters like CR, LF).
639   // http://www.w3.org/TR/XMLHttpRequest/
640   {
641     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("cOnNeCt", std::string()));
642     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("tRaCk", std::string()));
643     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("tRaCe", std::string()));
644     ASSERT_EQ(PP_ERROR_NOACCESS,
645         OpenUntrusted("POST\x0d\x0ax-csrf-token:\x20test1234", std::string()));
646   }
647   // HTTP methods are restricted only for untrusted loaders. Try all headers
648   // that are forbidden by http://www.w3.org/TR/XMLHttpRequest/.
649   {
650     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Accept-Charset:\n"));
651     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Accept-Encoding:\n"));
652     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Connection:\n"));
653     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Content-Length:\n"));
654     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Cookie:\n"));
655     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Cookie2:\n"));
656     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Date:\n"));
657     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Dnt:\n"));
658     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Expect:\n"));
659     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Host:\n"));
660     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Keep-Alive:\n"));
661     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Referer:\n"));
662     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "TE:\n"));
663     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Trailer:\n"));
664     ASSERT_EQ(PP_ERROR_NOACCESS,
665               OpenUntrusted("GET", "Transfer-Encoding:\n"));
666     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Upgrade:\n"));
667     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "User-Agent:\n"));
668     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Via:\n"));
669     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted(
670         "GET", "Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA==:\n"));
671     ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Sec-foo:\n"));
672   }
673   // Untrusted requests with custom referrer should fail.
674   {
675     pp::URLRequestInfo request(instance_);
676     request.SetCustomReferrerURL("http://www.google.com/");
677 
678     int32_t rv = OpenUntrusted(request, NULL);
679     if (rv != PP_ERROR_NOACCESS)
680       return ReportError(
681           "Untrusted request with custom referrer restriction", rv);
682   }
683   // Untrusted requests with custom transfer encodings should fail.
684   {
685     pp::URLRequestInfo request(instance_);
686     request.SetCustomContentTransferEncoding("foo");
687 
688     int32_t rv = OpenUntrusted(request, NULL);
689     if (rv != PP_ERROR_NOACCESS)
690       return ReportError(
691           "Untrusted request with content-transfer-encoding restriction", rv);
692   }
693 
694   PASS();
695 }
696 
TestTrustedHttpRequests()697 std::string TestURLLoader::TestTrustedHttpRequests() {
698   // Trusted requests can use restricted methods.
699   {
700     ASSERT_EQ(PP_OK, OpenTrusted("cOnNeCt", std::string()));
701     ASSERT_EQ(PP_OK, OpenTrusted("tRaCk", std::string()));
702     ASSERT_EQ(PP_OK, OpenTrusted("tRaCe", std::string()));
703   }
704   // Trusted requests can use restricted headers.
705   {
706     ASSERT_EQ(PP_OK, OpenTrusted("GET", "Accept-Charset:\n"));
707     ASSERT_EQ(PP_OK, OpenTrusted("GET", "Accept-Encoding:\n"));
708     ASSERT_EQ(PP_OK, OpenTrusted("GET", "Connection:\n"));
709     ASSERT_EQ(PP_OK, OpenTrusted("GET", "Cookie:\n"));
710     ASSERT_EQ(PP_OK, OpenTrusted("GET", "Date:\n"));
711     ASSERT_EQ(PP_OK, OpenTrusted("GET", "DNT:\n"));
712     ASSERT_EQ(PP_OK, OpenTrusted("GET", "Expect:\n"));
713 
714     // Host header is still forbidden because it can conflict with specific URL.
715 
716     ASSERT_EQ(PP_OK, OpenTrusted("GET", "Referer:\n"));
717     ASSERT_EQ(PP_OK, OpenTrusted("GET", "User-Agent:\n"));
718     ASSERT_EQ(PP_OK, OpenTrusted("GET", "Via:\n"));
719     ASSERT_EQ(PP_OK, OpenTrusted("GET", "Sec-foo:\n"));
720   }
721   // Trusted requests with custom referrer should succeed.
722   {
723     pp::URLRequestInfo request(instance_);
724     request.SetCustomReferrerURL("http://www.referer.com/");
725     request.SetHeaders("Referer: http://www.referer.com/");
726 
727     int32_t rv = OpenTrusted(request, NULL);
728     if (rv != PP_OK)
729       return ReportError("Trusted request with custom referrer", rv);
730   }
731   // Trusted requests with custom transfer encodings should succeed.
732   {
733     pp::URLRequestInfo request(instance_);
734     request.SetCustomContentTransferEncoding("foo");
735 
736     int32_t rv = OpenTrusted(request, NULL);
737     if (rv != PP_OK)
738       return ReportError(
739           "Trusted request with content-transfer-encoding failed", rv);
740   }
741 
742   PASS();
743 }
744 
745 // This test should cause a redirect and ensure that the loader follows it.
TestFollowURLRedirect()746 std::string TestURLLoader::TestFollowURLRedirect() {
747   pp::URLRequestInfo request(instance_);
748   // This prefix causes the test server to return a 301 redirect.
749   std::string redirect_prefix("/server-redirect?");
750   // We need an absolute path for the redirect to actually work.
751   std::string redirect_url =
752       GetReachableAbsoluteURL("test_url_loader_data/hello.txt");
753   request.SetURL(redirect_prefix.append(redirect_url));
754   return LoadAndCompareBody(request, "hello\n");
755 }
756 
757 // This test should cause a redirect and ensure that the loader runs
758 // the callback, rather than following the redirect.
TestAuditURLRedirect()759 std::string TestURLLoader::TestAuditURLRedirect() {
760   pp::URLRequestInfo request(instance_);
761   // This path will cause the server to return a 301 redirect.
762   // This prefix causes the test server to return a 301 redirect.
763   std::string redirect_prefix("/server-redirect?");
764   // We need an absolute path for the redirect to actually work.
765   std::string redirect_url =
766       GetReachableAbsoluteURL("test_url_loader_data/hello.txt");
767   request.SetURL(redirect_prefix.append(redirect_url));
768   request.SetFollowRedirects(false);
769 
770   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
771 
772   pp::URLLoader loader(instance_);
773   callback.WaitForResult(loader.Open(request, callback.GetCallback()));
774   CHECK_CALLBACK_BEHAVIOR(callback);
775   ASSERT_EQ(PP_OK, callback.result());
776 
777   // Checks that the response indicates a redirect, and that the URL
778   // is correct.
779   pp::URLResponseInfo response_info(loader.GetResponseInfo());
780   if (response_info.is_null())
781     return "URLLoader::GetResponseInfo returned null";
782   int32_t status_code = response_info.GetStatusCode();
783   if (status_code != 301)
784     return "Response status should be 301";
785 
786   // Test that the paused loader can be resumed.
787   callback.WaitForResult(loader.FollowRedirect(callback.GetCallback()));
788   CHECK_CALLBACK_BEHAVIOR(callback);
789   ASSERT_EQ(PP_OK, callback.result());
790   std::string body;
791   std::string error = ReadEntireResponseBody(&loader, &body);
792   if (!error.empty())
793     return error;
794 
795   if (body != "hello\n")
796     return "URLLoader::FollowRedirect failed";
797 
798   PASS();
799 }
800 
801 // This test checks if the redirect restriction does not block acceptable cases
802 // of 307/308 GET and HEAD.
TestRestrictURLRedirectCommon()803 std::string TestURLLoader::TestRestrictURLRedirectCommon() {
804   std::string url = GetReachableAbsoluteURL("test_url_loader_data/hello.txt");
805   std::string redirect_307_prefix("/server-redirect-307?");
806 
807   {
808     // Default method is GET and will follow the redirect.
809     pp::URLRequestInfo request_for_default_307(instance_);
810     request_for_default_307.SetURL(redirect_307_prefix.append(url));
811     std::string result_for_default_307 =
812         LoadAndCompareBody(request_for_default_307, "hello\n");
813     if (!result_for_default_307.empty())
814       return result_for_default_307;
815   }
816 
817   {
818     // GET will follow the redirect.
819     pp::URLRequestInfo request_for_get_307(instance_);
820     request_for_get_307.SetURL(redirect_307_prefix.append(url));
821     request_for_get_307.SetMethod("GET");
822     std::string result_for_get_307 =
823         LoadAndCompareBody(request_for_get_307, "hello\n");
824     if (!result_for_get_307.empty())
825       return result_for_get_307;
826   }
827 
828   {
829     // HEAD will follow the redirect.
830     pp::URLRequestInfo request_for_head_307(instance_);
831     request_for_head_307.SetURL(redirect_307_prefix.append(url));
832     request_for_head_307.SetMethod("HEAD");
833     std::string result_for_head_307 =
834         LoadAndCompareBody(request_for_head_307, "");
835     if (!result_for_head_307.empty())
836       return result_for_head_307;
837   }
838 
839   std::string redirect_308_prefix("/server-redirect-308?");
840   {
841     // Default method is GET and will follow the redirect.
842     pp::URLRequestInfo request_for_default_308(instance_);
843     request_for_default_308.SetURL(redirect_308_prefix.append(url));
844     std::string result_for_default_308 =
845         LoadAndCompareBody(request_for_default_308, "hello\n");
846     if (!result_for_default_308.empty())
847       return result_for_default_308;
848   }
849 
850   {
851     // GET will follow the redirect.
852     pp::URLRequestInfo request_for_get_308(instance_);
853     request_for_get_308.SetURL(redirect_308_prefix.append(url));
854     request_for_get_308.SetMethod("GET");
855     std::string result_for_get_308 =
856         LoadAndCompareBody(request_for_get_308, "hello\n");
857     if (!result_for_get_308.empty())
858       return result_for_get_308;
859   }
860 
861   {
862     // HEAD will follow the redirect.
863     pp::URLRequestInfo request_for_head_308(instance_);
864     request_for_head_308.SetURL(redirect_308_prefix.append(url));
865     request_for_head_308.SetMethod("HEAD");
866     std::string result_for_head_308 =
867         LoadAndCompareBody(request_for_head_308, "");
868     if (!result_for_head_308.empty())
869       return result_for_head_308;
870   }
871 
872   PASS();
873 }
874 
875 // This test checks if the redirect restriction blocks the restricted cases of
876 // 307/308 POST.
TestRestrictURLRedirectEnabled()877 std::string TestURLLoader::TestRestrictURLRedirectEnabled() {
878   std::string url = GetReachableAbsoluteURL("test_url_loader_data/hello.txt");
879 
880   {
881     // POST will be blocked and fail.
882     std::string redirect_307_prefix("/server-redirect-307?");
883     pp::URLRequestInfo request_for_post_307(instance_);
884     request_for_post_307.SetURL(redirect_307_prefix.append(url));
885     request_for_post_307.SetMethod("POST");
886     std::string result_for_post_307 = LoadAndFail(request_for_post_307);
887     if (!result_for_post_307.empty())
888       return result_for_post_307;
889   }
890 
891   {
892     // POST will be blocked and fail.
893     pp::URLRequestInfo request_for_post_308(instance_);
894     std::string redirect_308_prefix("/server-redirect-308?");
895     request_for_post_308.SetURL(redirect_308_prefix.append(url));
896     request_for_post_308.SetMethod("POST");
897     std::string result_for_post_308 = LoadAndFail(request_for_post_308);
898     if (!result_for_post_308.empty())
899       return result_for_post_308;
900   }
901 
902   PASS();
903 }
904 
905 // This test checks if the redirect restriction does not block the restricted
906 // cases if the restriction is disabled.
TestRestrictURLRedirectDisabled()907 std::string TestURLLoader::TestRestrictURLRedirectDisabled() {
908   std::string url = GetReachableAbsoluteURL("test_url_loader_data/hello.txt");
909 
910   {
911     // POST will not be blocked, but follow the redirect.
912     std::string redirect_307_prefix("/server-redirect-307?");
913     pp::URLRequestInfo request_for_post_307(instance_);
914     request_for_post_307.SetURL(redirect_307_prefix.append(url));
915     request_for_post_307.SetMethod("POST");
916     std::string result_for_post_307 =
917         LoadAndCompareBody(request_for_post_307, "hello\n");
918     if (!result_for_post_307.empty())
919       return result_for_post_307;
920   }
921 
922   {
923     // POST will not be blocked, but follow the redirect.
924     pp::URLRequestInfo request_for_post_308(instance_);
925     std::string redirect_308_prefix("/server-redirect-308?");
926     request_for_post_308.SetURL(redirect_308_prefix.append(url));
927     request_for_post_308.SetMethod("POST");
928     std::string result_for_post_308 =
929         LoadAndCompareBody(request_for_post_308, "hello\n");
930     if (!result_for_post_308.empty())
931       return result_for_post_308;
932   }
933 
934   PASS();
935 }
936 
TestAbortCalls()937 std::string TestURLLoader::TestAbortCalls() {
938   pp::URLRequestInfo request(instance_);
939   request.SetURL("test_url_loader_data/hello.txt");
940 
941   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
942   int32_t rv;
943 
944   // Abort |Open()|.
945   {
946     rv = pp::URLLoader(instance_).Open(request, callback.GetCallback());
947   }
948   callback.WaitForAbortResult(rv);
949   CHECK_CALLBACK_BEHAVIOR(callback);
950 
951   // Abort |ReadResponseBody()|.
952   {
953     char buf[2] = { 0 };
954     {
955       pp::URLLoader loader(instance_);
956       callback.WaitForResult(loader.Open(request, callback.GetCallback()));
957       CHECK_CALLBACK_BEHAVIOR(callback);
958       ASSERT_EQ(PP_OK, callback.result());
959 
960       rv = loader.ReadResponseBody(buf, sizeof(buf), callback.GetCallback());
961     }  // Destroy |loader|.
962     callback.WaitForAbortResult(rv);
963     CHECK_CALLBACK_BEHAVIOR(callback);
964     if (rv == PP_OK_COMPLETIONPENDING) {
965       if (buf[0] || buf[1]) {
966         return "URLLoader::ReadResponseBody wrote data after resource "
967                "destruction.";
968       }
969     }
970   }
971 
972   // TODO(viettrungluu): More abort tests (but add basic tests first).
973   // Also test that Close() aborts properly. crbug.com/69457
974 
975   PASS();
976 }
977 
TestUntendedLoad()978 std::string TestURLLoader::TestUntendedLoad() {
979   pp::URLRequestInfo request(instance_);
980   request.SetURL("test_url_loader_data/hello.txt");
981   request.SetRecordDownloadProgress(true);
982   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
983 
984   pp::URLLoader loader(instance_);
985   callback.WaitForResult(loader.Open(request, callback.GetCallback()));
986   CHECK_CALLBACK_BEHAVIOR(callback);
987   ASSERT_EQ(PP_OK, callback.result());
988 
989   // We received the response callback. Yield until the network code has called
990   // the loader's didReceiveData and didFinishLoading methods before we give it
991   // another callback function, to make sure the loader works with no callback.
992   int64_t bytes_received = 0;
993   int64_t total_bytes_to_be_received = 0;
994   while (true) {
995     loader.GetDownloadProgress(&bytes_received, &total_bytes_to_be_received);
996     if (total_bytes_to_be_received <= 0)
997       return ReportError("URLLoader::GetDownloadProgress total size",
998                          static_cast<int32_t>(total_bytes_to_be_received));
999     if (bytes_received == total_bytes_to_be_received)
1000       break;
1001     // Yield if we're on the main thread, so that URLLoader can receive more
1002     // data.
1003     if (pp::Module::Get()->core()->IsMainThread()) {
1004       NestedEvent event(instance_->pp_instance());
1005       event.PostSignal(10);
1006       event.Wait();
1007     }
1008   }
1009   // The loader should now have the data and have finished successfully.
1010   std::string body;
1011   std::string error = ReadEntireResponseBody(&loader, &body);
1012   if (!error.empty())
1013     return error;
1014   if (body != "hello\n")
1015     return ReportError("Couldn't read data", callback.result());
1016 
1017   PASS();
1018 }
1019 
OpenWithPrefetchBufferThreshold(int32_t lower,int32_t upper)1020 int32_t TestURLLoader::OpenWithPrefetchBufferThreshold(int32_t lower,
1021                                                        int32_t upper) {
1022   pp::URLRequestInfo request(instance_);
1023   request.SetURL("test_url_loader_data/hello.txt");
1024   request.SetPrefetchBufferLowerThreshold(lower);
1025   request.SetPrefetchBufferUpperThreshold(upper);
1026 
1027   return OpenUntrusted(request, NULL);
1028 }
1029 
TestPrefetchBufferThreshold()1030 std::string TestURLLoader::TestPrefetchBufferThreshold() {
1031   int32_t rv = OpenWithPrefetchBufferThreshold(-1, 1);
1032   if (rv != PP_ERROR_FAILED) {
1033     return ReportError("The prefetch limits contained a negative value but "
1034                        "the URLLoader did not fail.", rv);
1035   }
1036 
1037   rv = OpenWithPrefetchBufferThreshold(0, 1);
1038   if (rv != PP_OK) {
1039     return ReportError("The prefetch buffer limits were legal values but "
1040                        "the URLLoader failed.", rv);
1041   }
1042 
1043   rv = OpenWithPrefetchBufferThreshold(1000, 1);
1044   if (rv != PP_ERROR_FAILED) {
1045     return ReportError("The lower buffer value was higher than the upper but "
1046                        "the URLLoader did not fail.", rv);
1047   }
1048 
1049   PASS();
1050 }
1051 
1052 // TODO(viettrungluu): This test properly belongs elsewhere. It tests that
1053 // Chrome properly tags URL requests made on behalf of Pepper plugins (with an
1054 // X-Requested-With header), but this isn't, strictly speaking, a PPAPI
1055 // behavior.
TestXRequestedWithHeader()1056 std::string TestURLLoader::TestXRequestedWithHeader() {
1057   pp::URLRequestInfo request(instance_);
1058   request.SetURL("/echoheader?X-Requested-With");
1059   // The name and version of the plugin is set from the command-line (see
1060   // chrome/test/ppapi/ppapi_test.cc.
1061   return LoadAndCompareBody(request, "PPAPITests/1.2.3");
1062 }
1063 
1064 // TODO(viettrungluu): Add tests for  Get{Upload,Download}Progress, Close
1065 // (including abort tests if applicable).
1066