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
) {
46 bool TestURLRequest::Init() {
47 ppb_url_request_interface_
= static_cast<const PPB_URLRequestInfo
*>(
48 pp::Module::Get()->GetBrowserInterface(PPB_URLREQUESTINFO_INTERFACE
));
49 ppb_url_loader_interface_
= static_cast<const PPB_URLLoader
*>(
50 pp::Module::Get()->GetBrowserInterface(PPB_URLLOADER_INTERFACE
));
51 ppb_url_response_interface_
= static_cast<const PPB_URLResponseInfo
*>(
52 pp::Module::Get()->GetBrowserInterface(PPB_URLRESPONSEINFO_INTERFACE
));
53 ppb_core_interface_
= static_cast<const PPB_Core
*>(
54 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE
));
55 ppb_var_interface_
= static_cast<const PPB_Var
*>(
56 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE
));
57 if (!ppb_url_request_interface_
)
58 instance_
->AppendError("PPB_URLRequestInfo interface not available");
59 if (!ppb_url_response_interface_
)
60 instance_
->AppendError("PPB_URLResponseInfo interface not available");
61 if (!ppb_core_interface_
)
62 instance_
->AppendError("PPB_Core interface not available");
63 if (!ppb_var_interface_
)
64 instance_
->AppendError("PPB_Var interface not available");
65 if (!ppb_url_loader_interface_
) {
66 instance_
->AppendError("PPB_URLLoader interface not available");
68 return EnsureRunningOverHTTP();
71 void TestURLRequest::RunTests(const std::string
& filter
) {
72 RUN_TEST(CreateAndIsURLRequestInfo
, filter
);
73 RUN_TEST(SetProperty
, filter
);
74 RUN_TEST(AppendDataToBody
, filter
);
75 RUN_TEST(AppendFileToBody
, filter
);
76 RUN_TEST(Stress
, filter
);
79 PP_Var
TestURLRequest::PP_MakeString(const char* s
) {
80 return ppb_var_interface_
->VarFromUtf8(s
, static_cast<int32_t>(strlen(s
)));
84 // PP_Resource Create(PP_Instance instance)
85 // PP_Bool IsURLRequestInfo(PP_Resource resource)
86 std::string
TestURLRequest::TestCreateAndIsURLRequestInfo() {
87 // Create: Invalid / non-existent instance -> invalid resource.
88 ASSERT_EQ(ppb_url_request_interface_
->Create(kInvalidInstance
),
90 ASSERT_EQ(ppb_url_request_interface_
->Create(kNotAnInstance
),
93 // Create: Valid instance -> valid resource.
94 PP_Resource url_request
= ppb_url_request_interface_
->Create(
95 instance_
->pp_instance());
96 ASSERT_NE(url_request
, kInvalidResource
);
99 // Invalid / non-existent / non-URLRequestInfo resource -> false.
101 ppb_url_request_interface_
->IsURLRequestInfo(kInvalidResource
));
103 ppb_url_request_interface_
->IsURLRequestInfo(kNotAResource
));
105 PP_Resource url_loader
=
106 ppb_url_loader_interface_
->Create(instance_
->pp_instance());
107 ASSERT_NE(kInvalidResource
, url_loader
);
109 ASSERT_NE(PP_TRUE
, ppb_url_request_interface_
->IsURLRequestInfo(url_loader
));
110 ppb_url_loader_interface_
->Close(url_loader
);
111 ppb_core_interface_
->ReleaseResource(url_loader
);
113 // IsURLRequestInfo: Current URLRequestInfo resource -> true.
115 if (PP_FALSE
== ppb_url_request_interface_
->IsURLRequestInfo(url_request
))
116 error
= "IsURLRequestInfo() failed with a current URLRequestInfo resource";
118 // IsURLRequestInfo: Released URLRequestInfo resource -> false.
119 ppb_core_interface_
->ReleaseResource(url_request
);
120 ASSERT_NE(PP_TRUE
, ppb_url_request_interface_
->IsURLRequestInfo(url_request
));
122 return error
; // == PASS() if empty.
126 // PP_Bool SetProperty(PP_Resource request,
127 // PP_URLRequestProperty property,
128 // struct PP_Var value);
129 std::string
TestURLRequest::TestSetProperty() {
130 struct PropertyTestData
{
131 PropertyTestData(PP_URLRequestProperty prop
,
132 const std::string
& name
,
133 PP_Var value
, PP_Bool expected
) :
134 property(prop
), property_name(name
),
135 var(value
), expected_value(expected
) {
136 // var has ref count of 1 on creation.
138 PP_URLRequestProperty property
;
139 std::string property_name
;
140 PP_Var var
; // Instance owner is responsible for releasing this var.
141 PP_Bool expected_value
;
144 // All bool properties should accept PP_TRUE and PP_FALSE, while rejecting
145 // all other variable types.
146 #define TEST_BOOL(_name) \
147 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_TRUE), PP_TRUE), \
148 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_TRUE), \
149 PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE), \
150 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
151 PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE), \
152 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
154 // These property types are always invalid for string properties.
155 #define TEST_STRING_INVALID(_name) \
156 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
157 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \
158 PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE), \
159 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
161 #define TEST_INT_INVALID(_name) \
162 PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE), \
163 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
164 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \
165 PropertyTestData(ID_STR(_name), PP_MakeString("notint"), PP_FALSE), \
166 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
168 // SetProperty accepts plenty of invalid values (malformed urls, negative
169 // thresholds, etc). Error checking is delayed until request opening (aka url
171 #define ID_STR(arg) arg, #arg
172 PropertyTestData test_data
[] = {
173 TEST_BOOL(PP_URLREQUESTPROPERTY_STREAMTOFILE
),
174 TEST_BOOL(PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS
),
175 TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS
),
176 TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS
),
177 TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS
),
178 TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS
),
179 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_URL
),
180 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_METHOD
),
181 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_HEADERS
),
182 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
183 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
184 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
185 TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
186 TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
187 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
188 PP_MakeString("http://www.google.com"), PP_TRUE
),
189 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
190 PP_MakeString("foo.jpg"), PP_TRUE
),
191 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
192 PP_MakeString("GET"), PP_TRUE
),
193 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
194 PP_MakeString("POST"), PP_TRUE
),
195 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
196 PP_MakeString("Accept: text/plain"), PP_TRUE
),
197 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
198 PP_MakeString(""), PP_TRUE
),
199 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
200 PP_MakeString("http://www.google.com"), PP_TRUE
),
201 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
202 PP_MakeString(""), PP_TRUE
),
203 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
204 PP_MakeUndefined(), PP_TRUE
),
206 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
207 PP_MakeString("base64"), PP_TRUE
),
209 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
210 PP_MakeString(""), PP_TRUE
),
212 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
213 PP_MakeUndefined(), PP_TRUE
),
215 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
216 PP_MakeString("My Crazy Plugin"), PP_TRUE
),
218 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
219 PP_MakeString(""), PP_TRUE
),
221 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
222 PP_MakeUndefined(), PP_TRUE
),
223 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
224 PP_MakeUndefined(), PP_FALSE
),
225 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
226 PP_MakeUndefined(), PP_FALSE
),
228 ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
229 PP_MakeString("Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA=="),
232 ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
233 PP_MakeString("Accept-Encoding: *\n"
234 "Accept-Charset: iso-8859-5, unicode-1-1;q=0.8"),
237 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
238 PP_MakeInt32(0), PP_TRUE
),
240 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
241 PP_MakeInt32(100), PP_TRUE
),
243 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
244 PP_MakeInt32(0), PP_TRUE
),
246 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
247 PP_MakeInt32(100), PP_TRUE
),
248 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
249 PP_MakeString("::::::::::::"), PP_TRUE
),
250 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
251 PP_MakeString("INVALID"), PP_TRUE
),
253 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
254 PP_MakeString("invalid"), PP_TRUE
),
256 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
257 PP_MakeInt32(-100), PP_TRUE
),
259 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
260 PP_MakeInt32(-100), PP_TRUE
),
265 PP_Resource url_request
= ppb_url_request_interface_
->Create(
266 instance_
->pp_instance());
267 if (url_request
== kInvalidResource
)
268 error
= "Failed to create a URLRequestInfo";
270 // Loop over all test data even if we encountered an error to release vars.
272 i
< sizeof(test_data
) / sizeof(test_data
[0]);
274 if (error
.empty() && test_data
[i
].expected_value
!=
275 ppb_url_request_interface_
->SetProperty(url_request
,
276 test_data
[i
].property
,
278 pp::Var
var(pp::Var::DontManage(), test_data
[i
].var
);
279 error
= std::string("Setting property ") +
280 test_data
[i
].property_name
+ " to " + var
.DebugString() +
281 " did not return " + (test_data
[i
].expected_value
? "True" : "False");
282 error
= test_data
[i
].property_name
;
284 ppb_var_interface_
->Release(test_data
[i
].var
);
287 ppb_core_interface_
->ReleaseResource(url_request
);
288 return error
; // == PASS() if empty.
291 std::string
TestURLRequest::LoadAndCompareBody(
292 PP_Resource url_request
, const std::string
& expected_body
) {
293 TestCompletionCallback
callback(instance_
->pp_instance(), PP_REQUIRED
);
295 PP_Resource url_loader
=
296 ppb_url_loader_interface_
->Create(instance_
->pp_instance());
297 ASSERT_NE(kInvalidResource
, url_loader
);
299 callback
.WaitForResult(ppb_url_loader_interface_
->Open(
300 url_loader
, url_request
,
301 callback
.GetCallback().pp_completion_callback()));
302 CHECK_CALLBACK_BEHAVIOR(callback
);
303 ASSERT_EQ(PP_OK
, callback
.result());
306 PP_Resource url_response
=
307 ppb_url_loader_interface_
->GetResponseInfo(url_loader
);
308 if (url_response
== kInvalidResource
) {
309 error
= "PPB_URLLoader::GetResponseInfo() returned invalid resource";
311 PP_Var status
= ppb_url_response_interface_
->GetProperty(
312 url_response
, PP_URLRESPONSEPROPERTY_STATUSCODE
);
313 if (status
.type
!= PP_VARTYPE_INT32
&& status
.value
.as_int
!= 200)
314 error
= ReportError("PPB_URLLoader::Open() status", status
.value
.as_int
);
316 std::string actual_body
;
317 for (; error
.empty();) { // Read the entire body in this loop.
318 const size_t kBufferSize
= 32;
319 char buf
[kBufferSize
];
320 callback
.WaitForResult(ppb_url_loader_interface_
->ReadResponseBody(
321 url_loader
, buf
, kBufferSize
,
322 callback
.GetCallback().pp_completion_callback()));
323 if (callback
.failed())
324 error
.assign(callback
.errors());
325 else if (callback
.result() < PP_OK
)
326 error
.assign(ReportError("PPB_URLLoader::ReadResponseBody()",
328 if (callback
.result() <= PP_OK
|| callback
.failed())
330 actual_body
.append(buf
, callback
.result());
332 if (actual_body
!= expected_body
)
333 error
= "PPB_URLLoader::ReadResponseBody() read unexpected response.";
335 ppb_core_interface_
->ReleaseResource(url_response
);
337 ppb_url_loader_interface_
->Close(url_loader
);
338 ppb_core_interface_
->ReleaseResource(url_loader
);
343 // PP_Bool AppendDataToBody(
344 // PP_Resource request, const void* data, uint32_t len);
345 std::string
TestURLRequest::TestAppendDataToBody() {
346 PP_Resource url_request
= ppb_url_request_interface_
->Create(
347 instance_
->pp_instance());
348 ASSERT_NE(url_request
, kInvalidResource
);
350 std::string
postdata("sample postdata");
351 PP_Var post_string_var
= PP_MakeString("POST");
352 PP_Var echo_string_var
= PP_MakeString("/echo");
354 // NULL pointer causes a crash. In general PPAPI implementation does not
355 // test for NULL because they are just a special case of bad pointers that
356 // are not detectable if set to point to an object that does not exist.
358 // Invalid resource should fail.
359 ASSERT_EQ(PP_FALSE
, ppb_url_request_interface_
->AppendDataToBody(
360 kInvalidResource
, postdata
.data(),
361 static_cast<uint32_t>(postdata
.length())));
363 // Append data and POST to echoing web server.
364 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->SetProperty(
365 url_request
, PP_URLREQUESTPROPERTY_METHOD
, post_string_var
));
366 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->SetProperty(
367 url_request
, PP_URLREQUESTPROPERTY_URL
, echo_string_var
));
369 // Append data to body and verify the body is what we expect.
370 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->AppendDataToBody(
371 url_request
, postdata
.data(),
372 static_cast<uint32_t>(postdata
.length())));
373 std::string error
= LoadAndCompareBody(url_request
, postdata
);
375 ppb_var_interface_
->Release(post_string_var
);
376 ppb_var_interface_
->Release(echo_string_var
);
377 ppb_core_interface_
->ReleaseResource(url_request
);
378 return error
; // == PASS() if empty.
381 std::string
TestURLRequest::TestAppendFileToBody() {
382 PP_Resource url_request
= ppb_url_request_interface_
->Create(
383 instance_
->pp_instance());
384 ASSERT_NE(url_request
, kInvalidResource
);
386 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
388 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
389 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
390 CHECK_CALLBACK_BEHAVIOR(callback
);
391 ASSERT_EQ(PP_OK
, callback
.result());
393 pp::FileRef
ref(file_system
, "/test_file");
394 pp::FileIO
io(instance_
);
395 callback
.WaitForResult(io
.Open(ref
,
396 PP_FILEOPENFLAG_CREATE
| PP_FILEOPENFLAG_WRITE
,
397 callback
.GetCallback()));
398 CHECK_CALLBACK_BEHAVIOR(callback
);
399 ASSERT_EQ(PP_OK
, callback
.result());
401 std::string append_data
= "hello\n";
402 callback
.WaitForResult(io
.Write(0,
404 static_cast<int32_t>(append_data
.size()),
405 callback
.GetCallback()));
406 CHECK_CALLBACK_BEHAVIOR(callback
);
407 ASSERT_EQ(static_cast<int32_t>(append_data
.size()), callback
.result());
409 PP_Var post_string_var
= PP_MakeString("POST");
410 PP_Var echo_string_var
= PP_MakeString("/echo");
412 // NULL pointer causes a crash. In general PPAPI implementation does not
413 // test for NULL because they are just a special case of bad pointers that
414 // are not detectable if set to point to an object that does not exist.
416 // Invalid resource should fail.
417 ASSERT_EQ(PP_FALSE
, ppb_url_request_interface_
->AppendFileToBody(
418 kInvalidResource
, ref
.pp_resource(), 0, -1, 0));
420 // Append data and POST to echoing web server.
421 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->SetProperty(
422 url_request
, PP_URLREQUESTPROPERTY_METHOD
, post_string_var
));
423 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->SetProperty(
424 url_request
, PP_URLREQUESTPROPERTY_URL
, echo_string_var
));
426 // Append file to body and verify the body is what we expect.
427 ASSERT_EQ(PP_TRUE
, ppb_url_request_interface_
->AppendFileToBody(
428 url_request
, ref
.pp_resource(), 0, -1, 0));
429 std::string error
= LoadAndCompareBody(url_request
, append_data
);
431 ppb_var_interface_
->Release(post_string_var
);
432 ppb_var_interface_
->Release(echo_string_var
);
433 ppb_core_interface_
->ReleaseResource(url_request
);
434 return error
; // == PASS() if empty.
437 // Allocates and manipulates a large number of resources.
438 std::string
TestURLRequest::TestStress() {
439 const int kManyResources
= 500;
440 PP_Resource url_request_info
[kManyResources
];
443 int num_created
= kManyResources
;
444 for (int i
= 0; i
< kManyResources
; i
++) {
445 url_request_info
[i
] = ppb_url_request_interface_
->Create(
446 instance_
->pp_instance());
447 if (url_request_info
[i
] == kInvalidResource
) {
448 error
= "Create() failed";
449 } else if (PP_FALSE
== ppb_url_request_interface_
->IsURLRequestInfo(
450 url_request_info
[i
])) {
451 error
= "IsURLRequestInfo() failed";
452 } else if (PP_FALSE
== ppb_url_request_interface_
->SetProperty(
454 PP_URLREQUESTPROPERTY_STREAMTOFILE
,
455 PP_MakeBool(PP_FALSE
))) {
456 error
= "SetProperty() failed";
458 if (!error
.empty()) {
463 for (int i
= 0; i
< num_created
; i
++) {
464 ppb_core_interface_
->ReleaseResource(url_request_info
[i
]);
466 ppb_url_request_interface_
->IsURLRequestInfo(url_request_info
[i
]))
467 error
= "IsURLREquestInfo() succeeded after release";
469 return error
; // == PASS() if empty.