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.
5 // Tests PPB_URLRequestInfo interface.
7 #include "ppapi/tests/test_url_request.h"
12 #include "ppapi/c/dev/ppb_testing_dev.h"
13 #include "ppapi/c/ppb_file_io.h"
14 #include "ppapi/cpp/completion_callback.h"
15 #include "ppapi/cpp/file_io.h"
16 #include "ppapi/cpp/file_ref.h"
17 #include "ppapi/cpp/file_system.h"
18 #include "ppapi/cpp/instance.h"
19 #include "ppapi/cpp/var.h"
20 #include "ppapi/tests/test_utils.h"
21 #include "ppapi/tests/testing_instance.h"
23 REGISTER_TEST_CASE(URLRequest);
26 // TODO(polina): move these to test_case.h/cc since other NaCl tests use them?
28 const PP_Resource kInvalidResource = 0;
29 const PP_Instance kInvalidInstance = 0;
31 // These should not exist.
32 // The bottom 2 bits are used to differentiate between different id types.
33 // 00 - module, 01 - instance, 10 - resource, 11 - var.
34 const PP_Instance kNotAnInstance = 0xFFFFF0;
35 const PP_Resource kNotAResource = 0xAAAAA0;
38 TestURLRequest::TestURLRequest(TestingInstance* instance)
40 ppb_url_request_interface_(NULL),
41 ppb_url_loader_interface_(NULL),
42 ppb_url_response_interface_(NULL),
43 ppb_core_interface_(NULL),
44 ppb_var_interface_(NULL),
45 url_loader_(kInvalidResource) {
48 bool TestURLRequest::Init() {
49 ppb_url_request_interface_ = static_cast<const PPB_URLRequestInfo*>(
50 pp::Module::Get()->GetBrowserInterface(PPB_URLREQUESTINFO_INTERFACE));
51 ppb_url_loader_interface_ = static_cast<const PPB_URLLoader*>(
52 pp::Module::Get()->GetBrowserInterface(PPB_URLLOADER_INTERFACE));
53 ppb_url_response_interface_ = static_cast<const PPB_URLResponseInfo*>(
54 pp::Module::Get()->GetBrowserInterface(PPB_URLRESPONSEINFO_INTERFACE));
55 ppb_core_interface_ = static_cast<const PPB_Core*>(
56 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
57 ppb_var_interface_ = static_cast<const PPB_Var*>(
58 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE));
59 if (!ppb_url_request_interface_)
60 instance_->AppendError("PPB_URLRequestInfo interface not available");
61 if (!ppb_url_response_interface_)
62 instance_->AppendError("PPB_URLResponseInfo interface not available");
63 if (!ppb_core_interface_)
64 instance_->AppendError("PPB_Core interface not available");
65 if (!ppb_var_interface_)
66 instance_->AppendError("PPB_Var interface not available");
67 if (!ppb_url_loader_interface_) {
68 instance_->AppendError("PPB_URLLoader interface not available");
70 url_loader_ = ppb_url_loader_interface_->Create(instance_->pp_instance());
71 if (url_loader_ == kInvalidResource)
72 instance_->AppendError("Failed to create URLLoader");
74 return EnsureRunningOverHTTP();
77 void TestURLRequest::RunTests(const std::string& filter) {
78 RUN_TEST(CreateAndIsURLRequestInfo, filter);
79 RUN_TEST(SetProperty, filter);
80 RUN_TEST(AppendDataToBody, filter);
81 RUN_TEST(AppendFileToBody, filter);
82 RUN_TEST(Stress, filter);
85 PP_Var TestURLRequest::PP_MakeString(const char* s) {
86 return ppb_var_interface_->VarFromUtf8(s, strlen(s));
90 // PP_Resource Create(PP_Instance instance)
91 // PP_Bool IsURLRequestInfo(PP_Resource resource)
92 std::string TestURLRequest::TestCreateAndIsURLRequestInfo() {
93 // Create: Invalid / non-existent instance -> invalid resource.
94 ASSERT_EQ(ppb_url_request_interface_->Create(kInvalidInstance),
96 ASSERT_EQ(ppb_url_request_interface_->Create(kNotAnInstance),
99 // Create: Valid instance -> valid resource.
100 PP_Resource url_request = ppb_url_request_interface_->Create(
101 instance_->pp_instance());
102 ASSERT_NE(url_request, kInvalidResource);
105 // Invalid / non-existent / non-URLRequestInfo resource -> false.
107 ppb_url_request_interface_->IsURLRequestInfo(kInvalidResource));
109 ppb_url_request_interface_->IsURLRequestInfo(kNotAResource));
110 ASSERT_NE(PP_TRUE, ppb_url_request_interface_->IsURLRequestInfo(url_loader_));
112 // IsURLRequestInfo: Current URLRequestInfo resource -> true.
114 if (PP_FALSE == ppb_url_request_interface_->IsURLRequestInfo(url_request))
115 error = "IsURLRequestInfo() failed with a current URLRequestInfo resource";
117 // IsURLRequestInfo: Released URLRequestInfo resource -> false.
118 ppb_core_interface_->ReleaseResource(url_request);
119 ASSERT_NE(PP_TRUE, ppb_url_request_interface_->IsURLRequestInfo(url_request));
121 return error; // == PASS() if empty.
125 // PP_Bool SetProperty(PP_Resource request,
126 // PP_URLRequestProperty property,
127 // struct PP_Var value);
128 std::string TestURLRequest::TestSetProperty() {
129 struct PropertyTestData {
130 PropertyTestData(PP_URLRequestProperty prop,
131 const std::string& name,
132 PP_Var value, PP_Bool expected) :
133 property(prop), property_name(name),
134 var(value), expected_value(expected) {
135 // var has ref count of 1 on creation.
137 PP_URLRequestProperty property;
138 std::string property_name;
139 PP_Var var; // Instance owner is responsible for releasing this var.
140 PP_Bool expected_value;
143 // All bool properties should accept PP_TRUE and PP_FALSE, while rejecting
144 // all other variable types.
145 #define TEST_BOOL(_name) \
146 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_TRUE), PP_TRUE), \
147 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_TRUE), \
148 PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE), \
149 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
150 PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE), \
151 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
153 // These property types are always invalid for string properties.
154 #define TEST_STRING_INVALID(_name) \
155 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
156 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \
157 PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE), \
158 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
160 #define TEST_INT_INVALID(_name) \
161 PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE), \
162 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
163 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \
164 PropertyTestData(ID_STR(_name), PP_MakeString("notint"), PP_FALSE), \
165 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
167 // SetProperty accepts plenty of invalid values (malformed urls, negative
168 // thresholds, etc). Error checking is delayed until request opening (aka url
170 #define ID_STR(arg) arg, #arg
171 PropertyTestData test_data[] = {
172 TEST_BOOL(PP_URLREQUESTPROPERTY_STREAMTOFILE),
173 TEST_BOOL(PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS),
174 TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS),
175 TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS),
176 TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS),
177 TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS),
178 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_URL),
179 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_METHOD),
180 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_HEADERS),
181 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL),
182 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING),
183 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT),
184 TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD),
185 TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD),
186 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL),
187 PP_MakeString("http://www.google.com"), PP_TRUE),
188 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL),
189 PP_MakeString("foo.jpg"), PP_TRUE),
190 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD),
191 PP_MakeString("GET"), PP_TRUE),
192 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD),
193 PP_MakeString("POST"), PP_TRUE),
194 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS),
195 PP_MakeString("Accept: text/plain"), PP_TRUE),
196 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS),
197 PP_MakeString(""), PP_TRUE),
198 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL),
199 PP_MakeString("http://www.google.com"), PP_TRUE),
200 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL),
201 PP_MakeString(""), PP_TRUE),
202 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL),
203 PP_MakeUndefined(), PP_TRUE),
205 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING),
206 PP_MakeString("base64"), PP_TRUE),
208 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING),
209 PP_MakeString(""), PP_TRUE),
211 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING),
212 PP_MakeUndefined(), PP_TRUE),
214 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT),
215 PP_MakeString("My Crazy Plugin"), PP_TRUE),
217 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT),
218 PP_MakeString(""), PP_TRUE),
220 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT),
221 PP_MakeUndefined(), PP_TRUE),
222 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL),
223 PP_MakeUndefined(), PP_FALSE),
224 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD),
225 PP_MakeUndefined(), PP_FALSE),
227 ID_STR(PP_URLREQUESTPROPERTY_HEADERS),
228 PP_MakeString("Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA=="),
231 ID_STR(PP_URLREQUESTPROPERTY_HEADERS),
232 PP_MakeString("Accept-Encoding: *\n"
233 "Accept-Charset: iso-8859-5, unicode-1-1;q=0.8"),
236 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD),
237 PP_MakeInt32(0), PP_TRUE),
239 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD),
240 PP_MakeInt32(100), PP_TRUE),
242 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD),
243 PP_MakeInt32(0), PP_TRUE),
245 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD),
246 PP_MakeInt32(100), PP_TRUE),
247 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL),
248 PP_MakeString("::::::::::::"), PP_TRUE),
249 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD),
250 PP_MakeString("INVALID"), PP_TRUE),
252 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING),
253 PP_MakeString("invalid"), PP_TRUE),
255 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD),
256 PP_MakeInt32(-100), PP_TRUE),
258 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD),
259 PP_MakeInt32(-100), PP_TRUE),
264 PP_Resource url_request = ppb_url_request_interface_->Create(
265 instance_->pp_instance());
266 if (url_request == kInvalidResource)
267 error = "Failed to create a URLRequestInfo";
269 // Loop over all test data even if we encountered an error to release vars.
271 i < sizeof(test_data) / sizeof(test_data[0]);
273 if (error.empty() && test_data[i].expected_value !=
274 ppb_url_request_interface_->SetProperty(url_request,
275 test_data[i].property,
277 pp::Var var(pp::Var::DontManage(), test_data[i].var);
278 error = std::string("Setting property ") +
279 test_data[i].property_name + " to " + var.DebugString() +
280 " did not return " + (test_data[i].expected_value ? "True" : "False");
281 error = test_data[i].property_name;
283 ppb_var_interface_->Release(test_data[i].var);
286 ppb_core_interface_->ReleaseResource(url_request);
287 return error; // == PASS() if empty.
290 std::string TestURLRequest::LoadAndCompareBody(
291 PP_Resource url_request, const std::string& expected_body) {
292 TestCompletionCallback callback(instance_->pp_instance(), PP_REQUIRED);
293 callback.WaitForResult(ppb_url_loader_interface_->Open(
294 url_loader_, url_request,
295 callback.GetCallback().pp_completion_callback()));
296 CHECK_CALLBACK_BEHAVIOR(callback);
297 ASSERT_EQ(PP_OK, callback.result());
300 PP_Resource url_response =
301 ppb_url_loader_interface_->GetResponseInfo(url_loader_);
302 if (url_response == kInvalidResource) {
303 error = "PPB_URLLoader::GetResponseInfo() returned invalid resource";
305 PP_Var status = ppb_url_response_interface_->GetProperty(
306 url_response, PP_URLRESPONSEPROPERTY_STATUSCODE);
307 if (status.type != PP_VARTYPE_INT32 && status.value.as_int != 200)
308 error = ReportError("PPB_URLLoader::Open() status", status.value.as_int);
310 std::string actual_body;
311 for (; error.empty();) { // Read the entire body in this loop.
312 const size_t kBufferSize = 32;
313 char buf[kBufferSize];
314 callback.WaitForResult(ppb_url_loader_interface_->ReadResponseBody(
315 url_loader_, buf, kBufferSize,
316 callback.GetCallback().pp_completion_callback()));
317 if (callback.failed())
318 error.assign(callback.errors());
319 else if (callback.result() < PP_OK)
320 error.assign(ReportError("PPB_URLLoader::ReadResponseBody()",
322 if (callback.result() <= PP_OK || callback.failed())
324 actual_body.append(buf, callback.result());
326 if (actual_body != expected_body)
327 error = "PPB_URLLoader::ReadResponseBody() read unexpected response.";
329 ppb_core_interface_->ReleaseResource(url_response);
331 ppb_url_loader_interface_->Close(url_loader_);
336 // PP_Bool AppendDataToBody(
337 // PP_Resource request, const void* data, uint32_t len);
338 std::string TestURLRequest::TestAppendDataToBody() {
339 PP_Resource url_request = ppb_url_request_interface_->Create(
340 instance_->pp_instance());
341 ASSERT_NE(url_request, kInvalidResource);
343 std::string postdata("sample postdata");
344 PP_Var post_string_var = PP_MakeString("POST");
345 PP_Var echo_string_var = PP_MakeString("/echo");
347 // NULL pointer causes a crash. In general PPAPI implementation does not
348 // test for NULL because they are just a special case of bad pointers that
349 // are not detectable if set to point to an object that does not exist.
351 // Invalid resource should fail.
352 ASSERT_EQ(PP_FALSE, ppb_url_request_interface_->AppendDataToBody(
353 kInvalidResource, postdata.data(), postdata.length()));
355 // Append data and POST to echoing web server.
356 ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty(
357 url_request, PP_URLREQUESTPROPERTY_METHOD, post_string_var));
358 ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty(
359 url_request, PP_URLREQUESTPROPERTY_URL, echo_string_var));
361 // Append data to body and verify the body is what we expect.
362 ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->AppendDataToBody(
363 url_request, postdata.data(), postdata.length()));
364 std::string error = LoadAndCompareBody(url_request, postdata);
366 ppb_var_interface_->Release(post_string_var);
367 ppb_var_interface_->Release(echo_string_var);
368 ppb_core_interface_->ReleaseResource(url_request);
369 return error; // == PASS() if empty.
372 std::string TestURLRequest::TestAppendFileToBody() {
373 PP_Resource url_request = ppb_url_request_interface_->Create(
374 instance_->pp_instance());
375 ASSERT_NE(url_request, kInvalidResource);
377 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
379 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
380 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
381 CHECK_CALLBACK_BEHAVIOR(callback);
382 ASSERT_EQ(PP_OK, callback.result());
384 pp::FileRef ref(file_system, "/test_file");
385 pp::FileIO io(instance_);
386 callback.WaitForResult(io.Open(ref,
387 PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE,
388 callback.GetCallback()));
389 CHECK_CALLBACK_BEHAVIOR(callback);
390 ASSERT_EQ(PP_OK, callback.result());
392 std::string append_data = "hello\n";
393 callback.WaitForResult(io.Write(0,
396 callback.GetCallback()));
397 CHECK_CALLBACK_BEHAVIOR(callback);
398 ASSERT_EQ(static_cast<int32_t>(append_data.size()), callback.result());
400 PP_Var post_string_var = PP_MakeString("POST");
401 PP_Var echo_string_var = PP_MakeString("/echo");
403 // NULL pointer causes a crash. In general PPAPI implementation does not
404 // test for NULL because they are just a special case of bad pointers that
405 // are not detectable if set to point to an object that does not exist.
407 // Invalid resource should fail.
408 ASSERT_EQ(PP_FALSE, ppb_url_request_interface_->AppendFileToBody(
409 kInvalidResource, ref.pp_resource(), 0, -1, 0));
411 // Append data and POST to echoing web server.
412 ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty(
413 url_request, PP_URLREQUESTPROPERTY_METHOD, post_string_var));
414 ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty(
415 url_request, PP_URLREQUESTPROPERTY_URL, echo_string_var));
417 // Append file to body and verify the body is what we expect.
418 ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->AppendFileToBody(
419 url_request, ref.pp_resource(), 0, -1, 0));
420 std::string error = LoadAndCompareBody(url_request, append_data);
422 ppb_var_interface_->Release(post_string_var);
423 ppb_var_interface_->Release(echo_string_var);
424 ppb_core_interface_->ReleaseResource(url_request);
425 return error; // == PASS() if empty.
428 // Allocates and manipulates a large number of resources.
429 std::string TestURLRequest::TestStress() {
430 const int kManyResources = 500;
431 PP_Resource url_request_info[kManyResources];
434 int num_created = kManyResources;
435 for (int i = 0; i < kManyResources; i++) {
436 url_request_info[i] = ppb_url_request_interface_->Create(
437 instance_->pp_instance());
438 if (url_request_info[i] == kInvalidResource) {
439 error = "Create() failed";
440 } else if (PP_FALSE == ppb_url_request_interface_->IsURLRequestInfo(
441 url_request_info[i])) {
442 error = "IsURLRequestInfo() failed";
443 } else if (PP_FALSE == ppb_url_request_interface_->SetProperty(
445 PP_URLREQUESTPROPERTY_STREAMTOFILE,
446 PP_MakeBool(PP_FALSE))) {
447 error = "SetProperty() failed";
449 if (!error.empty()) {
454 for (int i = 0; i < num_created; i++) {
455 ppb_core_interface_->ReleaseResource(url_request_info[i]);
457 ppb_url_request_interface_->IsURLRequestInfo(url_request_info[i]))
458 error = "IsURLREquestInfo() succeeded after release";
460 return error; // == PASS() if empty.