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