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/cpp/completion_callback.h"
14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/var.h"
16 #include "ppapi/tests/test_utils.h"
17 #include "ppapi/tests/testing_instance.h"
19 REGISTER_TEST_CASE(URLRequest
);
22 // TODO(polina): move these to test_case.h/cc since other NaCl tests use them?
24 const PP_Resource kInvalidResource
= 0;
25 const PP_Instance kInvalidInstance
= 0;
27 // These should not exist.
28 // The bottom 2 bits are used to differentiate between different id types.
29 // 00 - module, 01 - instance, 10 - resource, 11 - var.
30 const PP_Instance kNotAnInstance
= 0xFFFFF0;
31 const PP_Resource kNotAResource
= 0xAAAAA0;
34 TestURLRequest::TestURLRequest(TestingInstance
* instance
)
36 ppb_url_request_interface_(NULL
),
37 ppb_url_loader_interface_(NULL
),
38 ppb_url_response_interface_(NULL
),
39 ppb_core_interface_(NULL
),
40 ppb_var_interface_(NULL
),
41 url_loader_(kInvalidResource
) {
44 bool TestURLRequest::Init() {
45 ppb_url_request_interface_
= static_cast<const PPB_URLRequestInfo
*>(
46 pp::Module::Get()->GetBrowserInterface(PPB_URLREQUESTINFO_INTERFACE
));
47 ppb_url_loader_interface_
= static_cast<const PPB_URLLoader
*>(
48 pp::Module::Get()->GetBrowserInterface(PPB_URLLOADER_INTERFACE
));
49 ppb_url_response_interface_
= static_cast<const PPB_URLResponseInfo
*>(
50 pp::Module::Get()->GetBrowserInterface(PPB_URLRESPONSEINFO_INTERFACE
));
51 ppb_core_interface_
= static_cast<const PPB_Core
*>(
52 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE
));
53 ppb_var_interface_
= static_cast<const PPB_Var
*>(
54 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE
));
55 if (!ppb_url_request_interface_
)
56 instance_
->AppendError("PPB_URLRequestInfo interface not available");
57 if (!ppb_url_response_interface_
)
58 instance_
->AppendError("PPB_URLResponseInfo interface not available");
59 if (!ppb_core_interface_
)
60 instance_
->AppendError("PPB_Core interface not available");
61 if (!ppb_var_interface_
)
62 instance_
->AppendError("PPB_Var interface not available");
63 if (!ppb_url_loader_interface_
) {
64 instance_
->AppendError("PPB_URLLoader interface not available");
66 url_loader_
= ppb_url_loader_interface_
->Create(instance_
->pp_instance());
67 if (url_loader_
== kInvalidResource
)
68 instance_
->AppendError("Failed to create URLLoader");
70 return EnsureRunningOverHTTP();
73 void TestURLRequest::RunTests(const std::string
& filter
) {
74 RUN_TEST(CreateAndIsURLRequestInfo
, filter
);
75 RUN_TEST(SetProperty
, filter
);
76 RUN_TEST(Stress
, filter
);
77 RUN_TEST(AppendDataToBody
, filter
);
80 PP_Var
TestURLRequest::PP_MakeString(const char* s
) {
81 return ppb_var_interface_
->VarFromUtf8(s
, strlen(s
));
85 // PP_Resource Create(PP_Instance instance)
86 // PP_Bool IsURLRequestInfo(PP_Resource resource)
87 std::string
TestURLRequest::TestCreateAndIsURLRequestInfo() {
88 // Create: Invalid / non-existent instance -> invalid resource.
89 ASSERT_EQ(ppb_url_request_interface_
->Create(kInvalidInstance
),
91 ASSERT_EQ(ppb_url_request_interface_
->Create(kNotAnInstance
),
94 // Create: Valid instance -> valid resource.
95 PP_Resource url_request
= ppb_url_request_interface_
->Create(
96 instance_
->pp_instance());
97 ASSERT_NE(url_request
, kInvalidResource
);
100 // Invalid / non-existent / non-URLRequestInfo resource -> false.
102 ppb_url_request_interface_
->IsURLRequestInfo(kInvalidResource
));
104 ppb_url_request_interface_
->IsURLRequestInfo(kNotAResource
));
105 ASSERT_NE(PP_TRUE
, ppb_url_request_interface_
->IsURLRequestInfo(url_loader_
));
107 // IsURLRequestInfo: Current URLRequestInfo resource -> true.
109 if (PP_FALSE
== ppb_url_request_interface_
->IsURLRequestInfo(url_request
))
110 error
= "IsURLRequestInfo() failed with a current URLRequestInfo resource";
112 // IsURLRequestInfo: Released URLRequestInfo resource -> false.
113 ppb_core_interface_
->ReleaseResource(url_request
);
114 ASSERT_NE(PP_TRUE
, ppb_url_request_interface_
->IsURLRequestInfo(url_request
));
116 return error
; // == PASS() if empty.
120 // PP_Bool SetProperty(PP_Resource request,
121 // PP_URLRequestProperty property,
122 // struct PP_Var value);
123 std::string
TestURLRequest::TestSetProperty() {
124 struct PropertyTestData
{
125 PropertyTestData(PP_URLRequestProperty prop
,
126 const std::string
& name
,
127 PP_Var value
, PP_Bool expected
) :
128 property(prop
), property_name(name
),
129 var(value
), expected_value(expected
) {
130 // var has ref count of 1 on creation.
132 PP_URLRequestProperty property
;
133 std::string property_name
;
134 PP_Var var
; // Instance owner is responsible for releasing this var.
135 PP_Bool expected_value
;
138 // All bool properties should accept PP_TRUE and PP_FALSE, while rejecting
139 // all other variable types.
140 #define TEST_BOOL(_name) \
141 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_TRUE), PP_TRUE), \
142 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_TRUE), \
143 PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE), \
144 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
145 PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE), \
146 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
148 // These property types are always invalid for string properties.
149 #define TEST_STRING_INVALID(_name) \
150 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
151 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \
152 PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE), \
153 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
155 #define TEST_INT_INVALID(_name) \
156 PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE), \
157 PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \
158 PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \
159 PropertyTestData(ID_STR(_name), PP_MakeString("notint"), PP_FALSE), \
160 PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
162 // SetProperty accepts plenty of invalid values (malformed urls, negative
163 // thresholds, etc). Error checking is delayed until request opening (aka url
165 #define ID_STR(arg) arg, #arg
166 PropertyTestData test_data
[] = {
167 TEST_BOOL(PP_URLREQUESTPROPERTY_STREAMTOFILE
),
168 TEST_BOOL(PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS
),
169 TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS
),
170 TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS
),
171 TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS
),
172 TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS
),
173 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_URL
),
174 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_METHOD
),
175 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_HEADERS
),
176 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
177 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
178 TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
179 TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
180 TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
181 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
182 PP_MakeString("http://www.google.com"), PP_TRUE
),
183 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
184 PP_MakeString("foo.jpg"), PP_TRUE
),
185 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
186 PP_MakeString("GET"), PP_TRUE
),
187 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
188 PP_MakeString("POST"), PP_TRUE
),
189 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
190 PP_MakeString("Accept: text/plain"), PP_TRUE
),
191 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
192 PP_MakeString(""), PP_TRUE
),
193 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
194 PP_MakeString("http://www.google.com"), PP_TRUE
),
195 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
196 PP_MakeString(""), PP_TRUE
),
197 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL
),
198 PP_MakeUndefined(), PP_TRUE
),
200 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
201 PP_MakeString("base64"), PP_TRUE
),
203 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
204 PP_MakeString(""), PP_TRUE
),
206 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
207 PP_MakeUndefined(), PP_TRUE
),
209 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
210 PP_MakeString("My Crazy Plugin"), PP_TRUE
),
212 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
213 PP_MakeString(""), PP_TRUE
),
215 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT
),
216 PP_MakeUndefined(), PP_TRUE
),
217 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
218 PP_MakeUndefined(), PP_FALSE
),
219 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
220 PP_MakeUndefined(), PP_FALSE
),
222 ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
223 PP_MakeString("Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA=="),
226 ID_STR(PP_URLREQUESTPROPERTY_HEADERS
),
227 PP_MakeString("Accept-Encoding: *\n"
228 "Accept-Charset: iso-8859-5, unicode-1-1;q=0.8"),
231 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
232 PP_MakeInt32(0), PP_TRUE
),
234 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
235 PP_MakeInt32(100), PP_TRUE
),
237 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
238 PP_MakeInt32(0), PP_TRUE
),
240 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
241 PP_MakeInt32(100), PP_TRUE
),
242 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL
),
243 PP_MakeString("::::::::::::"), PP_TRUE
),
244 PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD
),
245 PP_MakeString("INVALID"), PP_TRUE
),
247 ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING
),
248 PP_MakeString("invalid"), PP_TRUE
),
250 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD
),
251 PP_MakeInt32(-100), PP_TRUE
),
253 ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD
),
254 PP_MakeInt32(-100), PP_TRUE
),
259 PP_Resource url_request
= ppb_url_request_interface_
->Create(
260 instance_
->pp_instance());
261 if (url_request
== kInvalidResource
)
262 error
= "Failed to create a URLRequestInfo";
264 // Loop over all test data even if we encountered an error to release vars.
266 i
< sizeof(test_data
) / sizeof(test_data
[0]);
268 if (error
.empty() && test_data
[i
].expected_value
!=
269 ppb_url_request_interface_
->SetProperty(url_request
,
270 test_data
[i
].property
,
272 pp::Var
var(pp::Var::DontManage(), test_data
[i
].var
);
273 error
= std::string("Setting property ") +
274 test_data
[i
].property_name
+ " to " + var
.DebugString() +
275 " did not return " + (test_data
[i
].expected_value
? "True" : "False");
276 error
= test_data
[i
].property_name
;
278 ppb_var_interface_
->Release(test_data
[i
].var
);
281 ppb_core_interface_
->ReleaseResource(url_request
);
282 return error
; // == PASS() if empty.
285 std::string
TestURLRequest::LoadAndCompareBody(
286 PP_Resource url_request
, const std::string
& expected_body
) {
287 TestCompletionCallback
callback(instance_
->pp_instance(), PP_REQUIRED
);
288 callback
.WaitForResult(ppb_url_loader_interface_
->Open(
289 url_loader_
, url_request
,
290 callback
.GetCallback().pp_completion_callback()));
291 CHECK_CALLBACK_BEHAVIOR(callback
);
292 ASSERT_EQ(PP_OK
, callback
.result());
295 PP_Resource url_response
=
296 ppb_url_loader_interface_
->GetResponseInfo(url_loader_
);
297 if (url_response
== kInvalidResource
) {
298 error
= "PPB_URLLoader::GetResponseInfo() returned invalid resource";
300 PP_Var status
= ppb_url_response_interface_
->GetProperty(
301 url_response
, PP_URLRESPONSEPROPERTY_STATUSCODE
);
302 if (status
.type
!= PP_VARTYPE_INT32
&& status
.value
.as_int
!= 200)
303 error
= ReportError("PPB_URLLoader::Open() status", status
.value
.as_int
);
305 std::string actual_body
;
306 for (; error
.empty();) { // Read the entire body in this loop.
307 const size_t kBufferSize
= 32;
308 char buf
[kBufferSize
];
309 callback
.WaitForResult(ppb_url_loader_interface_
->ReadResponseBody(
310 url_loader_
, buf
, kBufferSize
,
311 callback
.GetCallback().pp_completion_callback()));
312 if (callback
.failed())
313 error
.assign(callback
.errors());
314 else if (callback
.result() < PP_OK
)
315 error
.assign(ReportError("PPB_URLLoader::ReadResponseBody()",
317 if (callback
.result() <= PP_OK
|| callback
.failed())
319 actual_body
.append(buf
, callback
.result());
321 if (actual_body
!= expected_body
)
322 error
= "PPB_URLLoader::ReadResponseBody() read unexpected response";
324 ppb_core_interface_
->ReleaseResource(url_response
);
329 // PP_Bool AppendDataToBody(
330 // PP_Resource request, const void* data, uint32_t len);
331 std::string
TestURLRequest::TestAppendDataToBody() {
332 PP_Resource url_request
= ppb_url_request_interface_
->Create(
333 instance_
->pp_instance());
334 ASSERT_NE(url_request
, kInvalidResource
);
336 std::string
postdata("sample postdata");
338 PP_Var post_string_var
= PP_MakeString("POST");
339 PP_Var echo_string_var
= PP_MakeString("/echo");
341 // NULL pointer causes a crash. In general PPAPI implementation does not
342 // test for NULL because they are just a special case of bad pointers that
343 // are not detectable if set to point to an object that does not exist.
345 // Invalid resource should fail.
346 if (PP_TRUE
== ppb_url_request_interface_
->AppendDataToBody(
347 kInvalidResource
, postdata
.data(), postdata
.length())) {
348 error
= "AppendDataToBody() succeeded with invalid resource";
349 // Append data and POST to echoing web server.
350 } else if (PP_FALSE
== ppb_url_request_interface_
->SetProperty(
351 url_request
, PP_URLREQUESTPROPERTY_METHOD
, post_string_var
)) {
352 error
= "SetProperty(METHOD) failed\n";
353 } else if (PP_FALSE
== ppb_url_request_interface_
->SetProperty(
354 url_request
, PP_URLREQUESTPROPERTY_URL
, echo_string_var
)) {
355 error
= "SetProperty(URL) failed\n";
356 } else if (PP_FALSE
== ppb_url_request_interface_
->AppendDataToBody(
357 url_request
, postdata
.data(), postdata
.length())) {
358 error
= "AppendDataToBody() failed";
360 // Check for success.
361 error
= LoadAndCompareBody(url_request
, postdata
);
364 ppb_var_interface_
->Release(post_string_var
);
365 ppb_var_interface_
->Release(echo_string_var
);
366 ppb_core_interface_
->ReleaseResource(url_request
);
367 return error
; // == PASS() if empty.
370 // TODO(elijahtaylor): add TestAppendFileToBody based on a broken disabled
371 // version from a NaCl test - see crbug.com/110242 for details.
373 // Allocates and manipulates a large number of resources.
374 std::string
TestURLRequest::TestStress() {
375 const int kManyResources
= 500;
376 PP_Resource url_request_info
[kManyResources
];
379 int num_created
= kManyResources
;
380 for (int i
= 0; i
< kManyResources
; i
++) {
381 url_request_info
[i
] = ppb_url_request_interface_
->Create(
382 instance_
->pp_instance());
383 if (url_request_info
[i
] == kInvalidResource
) {
384 error
= "Create() failed";
385 } else if (PP_FALSE
== ppb_url_request_interface_
->IsURLRequestInfo(
386 url_request_info
[i
])) {
387 error
= "IsURLRequestInfo() failed";
388 } else if (PP_FALSE
== ppb_url_request_interface_
->SetProperty(
390 PP_URLREQUESTPROPERTY_STREAMTOFILE
,
391 PP_MakeBool(PP_FALSE
))) {
392 error
= "SetProperty() failed";
394 if (!error
.empty()) {
399 for (int i
= 0; i
< num_created
; i
++) {
400 ppb_core_interface_
->ReleaseResource(url_request_info
[i
]);
402 ppb_url_request_interface_
->IsURLRequestInfo(url_request_info
[i
]))
403 error
= "IsURLREquestInfo() succeeded after release";
405 return error
; // == PASS() if empty.