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/ppb_file_io.h"
13 #include "ppapi/cpp/completion_callback.h"
14 #include "ppapi/cpp/file_io.h"
15 #include "ppapi/cpp/file_ref.h"
16 #include "ppapi/cpp/file_system.h"
17 #include "ppapi/cpp/instance.h"
18 #include "ppapi/cpp/var.h"
19 #include "ppapi/tests/test_utils.h"
20 #include "ppapi/tests/testing_instance.h"
22 REGISTER_TEST_CASE(URLRequest
);
25 // TODO(polina): move these to test_case.h/cc since other NaCl tests use them?
27 const PP_Resource kInvalidResource
= 0;
28 const PP_Instance kInvalidInstance
= 0;
30 // These should not exist.
31 // The bottom 2 bits are used to differentiate between different id types.
32 // 00 - module, 01 - instance, 10 - resource, 11 - var.
33 const PP_Instance kNotAnInstance
= 0xFFFFF0;
34 const PP_Resource kNotAResource
= 0xAAAAA0;
37 TestURLRequest::TestURLRequest(TestingInstance
* instance
)
39 ppb_url_request_interface_(NULL
),
40 ppb_url_loader_interface_(NULL
),
41 ppb_url_response_interface_(NULL
),
42 ppb_core_interface_(NULL
),
43 ppb_var_interface_(NULL
),
44 url_loader_(kInvalidResource
) {
47 bool TestURLRequest::Init() {
48 ppb_url_request_interface_
= static_cast<const PPB_URLRequestInfo
*>(
49 pp::Module::Get()->GetBrowserInterface(PPB_URLREQUESTINFO_INTERFACE
));
50 ppb_url_loader_interface_
= static_cast<const PPB_URLLoader
*>(
51 pp::Module::Get()->GetBrowserInterface(PPB_URLLOADER_INTERFACE
));
52 ppb_url_response_interface_
= static_cast<const PPB_URLResponseInfo
*>(
53 pp::Module::Get()->GetBrowserInterface(PPB_URLRESPONSEINFO_INTERFACE
));
54 ppb_core_interface_
= static_cast<const PPB_Core
*>(
55 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE
));
56 ppb_var_interface_
= static_cast<const PPB_Var
*>(
57 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE
));
58 if (!ppb_url_request_interface_
)
59 instance_
->AppendError("PPB_URLRequestInfo interface not available");
60 if (!ppb_url_response_interface_
)
61 instance_
->AppendError("PPB_URLResponseInfo interface not available");
62 if (!ppb_core_interface_
)
63 instance_
->AppendError("PPB_Core interface not available");
64 if (!ppb_var_interface_
)
65 instance_
->AppendError("PPB_Var interface not available");
66 if (!ppb_url_loader_interface_
) {
67 instance_
->AppendError("PPB_URLLoader interface not available");
69 url_loader_
= ppb_url_loader_interface_
->Create(instance_
->pp_instance());
70 if (url_loader_
== kInvalidResource
)
71 instance_
->AppendError("Failed to create URLLoader");
73 return EnsureRunningOverHTTP();
76 void TestURLRequest::RunTests(const std::string
& filter
) {
77 RUN_TEST(CreateAndIsURLRequestInfo
, filter
);
78 RUN_TEST(SetProperty
, filter
);
79 RUN_TEST(AppendDataToBody
, filter
);
80 RUN_TEST(AppendFileToBody
, filter
);
81 RUN_TEST(Stress
, filter
);
84 PP_Var
TestURLRequest::PP_MakeString(const char* s
) {
85 return ppb_var_interface_
->VarFromUtf8(s
, strlen(s
));
89 // PP_Resource Create(PP_Instance instance)
90 // PP_Bool IsURLRequestInfo(PP_Resource resource)
91 std::string
TestURLRequest::TestCreateAndIsURLRequestInfo() {
92 // Create: Invalid / non-existent instance -> invalid resource.
93 ASSERT_EQ(ppb_url_request_interface_
->Create(kInvalidInstance
),
95 ASSERT_EQ(ppb_url_request_interface_
->Create(kNotAnInstance
),
98 // Create: Valid instance -> valid resource.
99 PP_Resource url_request
= ppb_url_request_interface_
->Create(
100 instance_
->pp_instance());
101 ASSERT_NE(url_request
, kInvalidResource
);
104 // Invalid / non-existent / non-URLRequestInfo resource -> false.
106 ppb_url_request_interface_
->IsURLRequestInfo(kInvalidResource
));
108 ppb_url_request_interface_
->IsURLRequestInfo(kNotAResource
));
109 ASSERT_NE(PP_TRUE
, ppb_url_request_interface_
->IsURLRequestInfo(url_loader_
));
111 // IsURLRequestInfo: Current URLRequestInfo resource -> true.
113 if (PP_FALSE
== ppb_url_request_interface_
->IsURLRequestInfo(url_request
))
114 error
= "IsURLRequestInfo() failed with a current URLRequestInfo resource";
116 // IsURLRequestInfo: Released URLRequestInfo resource -> false.
117 ppb_core_interface_
->ReleaseResource(url_request
);
118 ASSERT_NE(PP_TRUE
, ppb_url_request_interface_
->IsURLRequestInfo(url_request
));
120 return error
; // == PASS() if empty.
124 // PP_Bool SetProperty(PP_Resource request,
125 // PP_URLRequestProperty property,
126 // struct PP_Var value);
127 std::string
TestURLRequest::TestSetProperty() {
128 struct PropertyTestData
{
129 PropertyTestData(PP_URLRequestProperty prop
,
130 const std::string
& name
,
131 PP_Var value
, PP_Bool expected
) :
132 property(prop
), property_name(name
),
133 var(value
), expected_value(expected
) {
134 // var has ref count of 1 on creation.
136 PP_URLRequestProperty property
;
137 std::string property_name
;
138 PP_Var var
; // Instance owner is responsible for releasing this var.
139 PP_Bool expected_value
;
142 // All bool properties should accept PP_TRUE and PP_FALSE, while rejecting
143 // all other variable types.
144 #define TEST_BOOL(_name) \
145 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_TRUE), PP_TRUE), \
146 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_TRUE), \
147 PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE), \
148 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
149 PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE), \
150 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
152 // These property types are always invalid for string properties.
153 #define TEST_STRING_INVALID(_name) \
154 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
155 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \
156 PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE), \
157 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
159 #define TEST_INT_INVALID(_name) \
160 PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE), \
161 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
162 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \
163 PropertyTestData(ID_STR(_name), PP_MakeString("notint"), PP_FALSE), \
164 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
166 // SetProperty accepts plenty of invalid values (malformed urls, negative
167 // thresholds, etc). Error checking is delayed until request opening (aka url
169 #define ID_STR(arg) arg, #arg
170 PropertyTestData test_data
[] = {
171 TEST_BOOL(PP_URLREQUESTPROPERTY_STREAMTOFILE
),
172 TEST_BOOL(PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS
),
173 TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS
),
174 TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS
),
175 TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS
),
176 TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS
),
177 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_URL
),
178 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_METHOD
),
179 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_HEADERS
),
180 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
181 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
182 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
183 TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
184 TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
185 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
186 PP_MakeString("http://www.google.com"), PP_TRUE
),
187 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
188 PP_MakeString("foo.jpg"), PP_TRUE
),
189 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
190 PP_MakeString("GET"), PP_TRUE
),
191 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
192 PP_MakeString("POST"), PP_TRUE
),
193 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
194 PP_MakeString("Accept: text/plain"), PP_TRUE
),
195 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
196 PP_MakeString(""), PP_TRUE
),
197 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
198 PP_MakeString("http://www.google.com"), PP_TRUE
),
199 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
200 PP_MakeString(""), PP_TRUE
),
201 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
202 PP_MakeUndefined(), PP_TRUE
),
204 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
205 PP_MakeString("base64"), PP_TRUE
),
207 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
208 PP_MakeString(""), PP_TRUE
),
210 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
211 PP_MakeUndefined(), PP_TRUE
),
213 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
214 PP_MakeString("My Crazy Plugin"), PP_TRUE
),
216 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
217 PP_MakeString(""), PP_TRUE
),
219 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
220 PP_MakeUndefined(), PP_TRUE
),
221 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
222 PP_MakeUndefined(), PP_FALSE
),
223 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
224 PP_MakeUndefined(), PP_FALSE
),
226 ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
227 PP_MakeString("Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA=="),
230 ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
231 PP_MakeString("Accept-Encoding: *\n"
232 "Accept-Charset: iso-8859-5, unicode-1-1;q=0.8"),
235 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
236 PP_MakeInt32(0), PP_TRUE
),
238 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
239 PP_MakeInt32(100), PP_TRUE
),
241 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
242 PP_MakeInt32(0), PP_TRUE
),
244 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
245 PP_MakeInt32(100), PP_TRUE
),
246 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
247 PP_MakeString("::::::::::::"), PP_TRUE
),
248 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
249 PP_MakeString("INVALID"), PP_TRUE
),
251 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
252 PP_MakeString("invalid"), PP_TRUE
),
254 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
255 PP_MakeInt32(-100), PP_TRUE
),
257 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
258 PP_MakeInt32(-100), PP_TRUE
),
263 PP_Resource url_request
= ppb_url_request_interface_
->Create(
264 instance_
->pp_instance());
265 if (url_request
== kInvalidResource
)
266 error
= "Failed to create a URLRequestInfo";
268 // Loop over all test data even if we encountered an error to release vars.
270 i
< sizeof(test_data
) / sizeof(test_data
[0]);
272 if (error
.empty() && test_data
[i
].expected_value
!=
273 ppb_url_request_interface_
->SetProperty(url_request
,
274 test_data
[i
].property
,
276 pp::Var
var(pp::Var::DontManage(), test_data
[i
].var
);
277 error
= std::string("Setting property ") +
278 test_data
[i
].property_name
+ " to " + var
.DebugString() +
279 " did not return " + (test_data
[i
].expected_value
? "True" : "False");
280 error
= test_data
[i
].property_name
;
282 ppb_var_interface_
->Release(test_data
[i
].var
);
285 ppb_core_interface_
->ReleaseResource(url_request
);
286 return error
; // == PASS() if empty.
289 std::string
TestURLRequest::LoadAndCompareBody(
290 PP_Resource url_request
, const std::string
& expected_body
) {
291 TestCompletionCallback
callback(instance_
->pp_instance(), PP_REQUIRED
);
292 callback
.WaitForResult(ppb_url_loader_interface_
->Open(
293 url_loader_
, url_request
,
294 callback
.GetCallback().pp_completion_callback()));
295 CHECK_CALLBACK_BEHAVIOR(callback
);
296 ASSERT_EQ(PP_OK
, callback
.result());
299 PP_Resource url_response
=
300 ppb_url_loader_interface_
->GetResponseInfo(url_loader_
);
301 if (url_response
== kInvalidResource
) {
302 error
= "PPB_URLLoader::GetResponseInfo() returned invalid resource";
304 PP_Var status
= ppb_url_response_interface_
->GetProperty(
305 url_response
, PP_URLRESPONSEPROPERTY_STATUSCODE
);
306 if (status
.type
!= PP_VARTYPE_INT32
&& status
.value
.as_int
!= 200)
307 error
= ReportError("PPB_URLLoader::Open() status", status
.value
.as_int
);
309 std::string actual_body
;
310 for (; error
.empty();) { // Read the entire body in this loop.
311 const size_t kBufferSize
= 32;
312 char buf
[kBufferSize
];
313 callback
.WaitForResult(ppb_url_loader_interface_
->ReadResponseBody(
314 url_loader_
, buf
, kBufferSize
,
315 callback
.GetCallback().pp_completion_callback()));
316 if (callback
.failed())
317 error
.assign(callback
.errors());
318 else if (callback
.result() < PP_OK
)
319 error
.assign(ReportError("PPB_URLLoader::ReadResponseBody()",
321 if (callback
.result() <= PP_OK
|| callback
.failed())
323 actual_body
.append(buf
, callback
.result());
325 if (actual_body
!= expected_body
)
326 error
= "PPB_URLLoader::ReadResponseBody() read unexpected response.";
328 ppb_core_interface_
->ReleaseResource(url_response
);
330 ppb_url_loader_interface_
->Close(url_loader_
);
335 // PP_Bool AppendDataToBody(
336 // PP_Resource request, const void* data, uint32_t len);
337 std::string
TestURLRequest::TestAppendDataToBody() {
338 PP_Resource url_request
= ppb_url_request_interface_
->Create(
339 instance_
->pp_instance());
340 ASSERT_NE(url_request
, kInvalidResource
);
342 std::string
postdata("sample postdata");
343 PP_Var post_string_var
= PP_MakeString("POST");
344 PP_Var echo_string_var
= PP_MakeString("/echo");
346 // NULL pointer causes a crash. In general PPAPI implementation does not
347 // test for NULL because they are just a special case of bad pointers that
348 // are not detectable if set to point to an object that does not exist.
350 // Invalid resource should fail.
351 ASSERT_EQ(PP_FALSE
, ppb_url_request_interface_
->AppendDataToBody(
352 kInvalidResource
, postdata
.data(), postdata
.length()));
354 // Append data and POST to echoing web server.
355 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->SetProperty(
356 url_request
, PP_URLREQUESTPROPERTY_METHOD
, post_string_var
));
357 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->SetProperty(
358 url_request
, PP_URLREQUESTPROPERTY_URL
, echo_string_var
));
360 // Append data to body and verify the body is what we expect.
361 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->AppendDataToBody(
362 url_request
, postdata
.data(), postdata
.length()));
363 std::string error
= LoadAndCompareBody(url_request
, postdata
);
365 ppb_var_interface_
->Release(post_string_var
);
366 ppb_var_interface_
->Release(echo_string_var
);
367 ppb_core_interface_
->ReleaseResource(url_request
);
368 return error
; // == PASS() if empty.
371 std::string
TestURLRequest::TestAppendFileToBody() {
372 PP_Resource url_request
= ppb_url_request_interface_
->Create(
373 instance_
->pp_instance());
374 ASSERT_NE(url_request
, kInvalidResource
);
376 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
378 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
379 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
380 CHECK_CALLBACK_BEHAVIOR(callback
);
381 ASSERT_EQ(PP_OK
, callback
.result());
383 pp::FileRef
ref(file_system
, "/test_file");
384 pp::FileIO
io(instance_
);
385 callback
.WaitForResult(io
.Open(ref
,
386 PP_FILEOPENFLAG_CREATE
| PP_FILEOPENFLAG_WRITE
,
387 callback
.GetCallback()));
388 CHECK_CALLBACK_BEHAVIOR(callback
);
389 ASSERT_EQ(PP_OK
, callback
.result());
391 std::string append_data
= "hello\n";
392 callback
.WaitForResult(io
.Write(0,
395 callback
.GetCallback()));
396 CHECK_CALLBACK_BEHAVIOR(callback
);
397 ASSERT_EQ(static_cast<int32_t>(append_data
.size()), callback
.result());
399 PP_Var post_string_var
= PP_MakeString("POST");
400 PP_Var echo_string_var
= PP_MakeString("/echo");
402 // NULL pointer causes a crash. In general PPAPI implementation does not
403 // test for NULL because they are just a special case of bad pointers that
404 // are not detectable if set to point to an object that does not exist.
406 // Invalid resource should fail.
407 ASSERT_EQ(PP_FALSE
, ppb_url_request_interface_
->AppendFileToBody(
408 kInvalidResource
, ref
.pp_resource(), 0, -1, 0));
410 // Append data and POST to echoing web server.
411 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->SetProperty(
412 url_request
, PP_URLREQUESTPROPERTY_METHOD
, post_string_var
));
413 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->SetProperty(
414 url_request
, PP_URLREQUESTPROPERTY_URL
, echo_string_var
));
416 // Append file to body and verify the body is what we expect.
417 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->AppendFileToBody(
418 url_request
, ref
.pp_resource(), 0, -1, 0));
419 std::string error
= LoadAndCompareBody(url_request
, append_data
);
421 ppb_var_interface_
->Release(post_string_var
);
422 ppb_var_interface_
->Release(echo_string_var
);
423 ppb_core_interface_
->ReleaseResource(url_request
);
424 return error
; // == PASS() if empty.
427 // Allocates and manipulates a large number of resources.
428 std::string
TestURLRequest::TestStress() {
429 const int kManyResources
= 500;
430 PP_Resource url_request_info
[kManyResources
];
433 int num_created
= kManyResources
;
434 for (int i
= 0; i
< kManyResources
; i
++) {
435 url_request_info
[i
] = ppb_url_request_interface_
->Create(
436 instance_
->pp_instance());
437 if (url_request_info
[i
] == kInvalidResource
) {
438 error
= "Create() failed";
439 } else if (PP_FALSE
== ppb_url_request_interface_
->IsURLRequestInfo(
440 url_request_info
[i
])) {
441 error
= "IsURLRequestInfo() failed";
442 } else if (PP_FALSE
== ppb_url_request_interface_
->SetProperty(
444 PP_URLREQUESTPROPERTY_STREAMTOFILE
,
445 PP_MakeBool(PP_FALSE
))) {
446 error
= "SetProperty() failed";
448 if (!error
.empty()) {
453 for (int i
= 0; i
< num_created
; i
++) {
454 ppb_core_interface_
->ReleaseResource(url_request_info
[i
]);
456 ppb_url_request_interface_
->IsURLRequestInfo(url_request_info
[i
]))
457 error
= "IsURLREquestInfo() succeeded after release";
459 return error
; // == PASS() if empty.