1 // Copyright (c) 2011 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 "content/test/plugin/plugin_geturl_test.h" 6 7 #include <stdio.h> 8 9 #include "base/basictypes.h" 10 #include "base/file_util.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_util.h" 13 #include "base/strings/utf_string_conversions.h" 14 15 // url for "self". The %22%22 is to make a statement for javascript to 16 // evaluate and return. 17 #define SELF_URL "javascript:window.location+\"\"" 18 19 // The identifier for the self url stream. 20 #define SELF_URL_STREAM_ID 1 21 22 // The identifier for the fetched url stream. 23 #define FETCHED_URL_STREAM_ID 2 24 25 // url for testing GetURL with a bogus URL. 26 #define BOGUS_URL "bogoproto:///x:/asdf.xysdhffieasdf.asdhj/" 27 28 // url for testing redirect notifications sent to plugins. 29 #define REDIRECT_SRC_URL \ 30 "http://mock.http/npapi/plugin_read_page_redirect_src.html" 31 32 // The notification id for the redirect notification url. 33 #define REDIRECT_SRC_URL_NOTIFICATION_ID 4 34 35 // The identifier for the bogus url stream. 36 #define BOGUS_URL_STREAM_ID 3 37 38 // The maximum chunk size of stream data. 39 #define STREAM_CHUNK 197 40 41 namespace NPAPIClient { 42 43 PluginGetURLTest::PluginGetURLTest(NPP id, NPNetscapeFuncs *host_functions) 44 : PluginTest(id, host_functions), 45 tests_started_(false), 46 tests_in_progress_(0), 47 test_file_(NULL), 48 expect_404_response_(false), 49 npn_evaluate_context_(false), 50 handle_url_redirects_(false), 51 received_url_redirect_notification_(false) { 52 } 53 54 PluginGetURLTest::~PluginGetURLTest() {} 55 56 NPError PluginGetURLTest::New(uint16 mode, int16 argc, const char* argn[], 57 const char* argv[], NPSavedData* saved) { 58 const char* page_not_found_url = GetArgValue("page_not_found_url", argc, 59 argn, argv); 60 if (page_not_found_url) { 61 page_not_found_url_ = page_not_found_url; 62 expect_404_response_ = true; 63 } 64 65 const char* fail_write_url = GetArgValue("fail_write_url", argc, 66 argn, argv); 67 if (fail_write_url) { 68 fail_write_url_ = fail_write_url; 69 } 70 71 const char* referrer_target_url = GetArgValue("ref_target", argc, 72 argn, argv); 73 if (referrer_target_url) { 74 referrer_target_url_ = referrer_target_url; 75 } 76 77 if (!base::strcasecmp(GetArgValue("name", argc, argn, argv), 78 "geturlredirectnotify")) { 79 handle_url_redirects_ = true; 80 } 81 return PluginTest::New(mode, argc, argn, argv, saved); 82 } 83 84 NPError PluginGetURLTest::SetWindow(NPWindow* pNPWindow) { 85 #if !defined(OS_MACOSX) 86 if (pNPWindow->window == NULL) 87 return NPERR_NO_ERROR; 88 #endif 89 90 if (!tests_started_) { 91 tests_started_ = true; 92 93 tests_in_progress_++; 94 95 if (expect_404_response_) { 96 HostFunctions()->geturl(id(), page_not_found_url_.c_str(), NULL); 97 return NPERR_NO_ERROR; 98 } else if (!fail_write_url_.empty()) { 99 HostFunctions()->geturl(id(), fail_write_url_.c_str(), NULL); 100 return NPERR_NO_ERROR; 101 } else if (!referrer_target_url_.empty()) { 102 HostFunctions()->pushpopupsenabledstate(id(), true); 103 HostFunctions()->geturl(id(), referrer_target_url_.c_str(), "_blank"); 104 HostFunctions()->poppopupsenabledstate(id()); 105 return NPERR_NO_ERROR; 106 } else if (handle_url_redirects_) { 107 HostFunctions()->geturlnotify( 108 id(), REDIRECT_SRC_URL, NULL, 109 reinterpret_cast<void*>(REDIRECT_SRC_URL_NOTIFICATION_ID)); 110 return NPERR_NO_ERROR; 111 } 112 113 std::string url = SELF_URL; 114 HostFunctions()->geturlnotify(id(), url.c_str(), NULL, 115 reinterpret_cast<void*>(SELF_URL_STREAM_ID)); 116 117 tests_in_progress_++; 118 std::string bogus_url = BOGUS_URL; 119 HostFunctions()->geturlnotify(id(), bogus_url.c_str(), NULL, 120 reinterpret_cast<void*>(BOGUS_URL_STREAM_ID)); 121 } 122 return NPERR_NO_ERROR; 123 } 124 125 NPError PluginGetURLTest::NewStream(NPMIMEType type, NPStream* stream, 126 NPBool seekable, uint16* stype) { 127 if (stream == NULL) { 128 SetError("NewStream got null stream"); 129 return NPERR_INVALID_PARAM; 130 } 131 132 if (test_completed()) { 133 return PluginTest::NewStream(type, stream, seekable, stype); 134 } 135 136 if (!referrer_target_url_.empty()) { 137 return NPERR_NO_ERROR; 138 } 139 140 COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData), 141 cast_validity_check); 142 143 if (expect_404_response_) { 144 NPObject *window_obj = NULL; 145 HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj); 146 if (!window_obj) { 147 SetError("Failed to get NPObject for plugin instance2"); 148 SignalTestCompleted(); 149 return NPERR_NO_ERROR; 150 } 151 152 std::string script = "javascript:document.title=\"OK\""; 153 NPString script_string; 154 script_string.UTF8Characters = script.c_str(); 155 script_string.UTF8Length = static_cast<unsigned int>(script.length()); 156 NPVariant result_var; 157 158 npn_evaluate_context_ = true; 159 HostFunctions()->evaluate(id(), window_obj, &script_string, &result_var); 160 npn_evaluate_context_ = false; 161 return NPERR_NO_ERROR; 162 } 163 164 if (!fail_write_url_.empty()) { 165 return NPERR_NO_ERROR; 166 } 167 168 169 unsigned long stream_id = reinterpret_cast<unsigned long>( 170 stream->notifyData); 171 172 switch (stream_id) { 173 case SELF_URL_STREAM_ID: 174 break; 175 case FETCHED_URL_STREAM_ID: 176 { 177 std::string filename = self_url_; 178 if (filename.find("file:///", 0) != 0) { 179 SetError("Test expects a file-url."); 180 break; 181 } 182 183 // TODO(evanm): use the net:: functions to convert file:// URLs to 184 // on-disk file paths. But it probably doesn't actually matter in 185 // this test. 186 187 #if defined(OS_WIN) 188 filename = filename.substr(8); // remove "file:///" 189 // Assume an ASCII path on Windows. 190 base::FilePath path = base::FilePath(ASCIIToWide(filename)); 191 #else 192 filename = filename.substr(7); // remove "file://" 193 base::FilePath path = base::FilePath(filename); 194 #endif 195 196 test_file_ = file_util::OpenFile(path, "r"); 197 if (!test_file_) { 198 SetError("Could not open source file"); 199 } 200 } 201 break; 202 case BOGUS_URL_STREAM_ID: 203 SetError("Unexpected NewStream for BOGUS_URL"); 204 break; 205 case REDIRECT_SRC_URL_NOTIFICATION_ID: 206 SetError("Should not redirect to URL when plugin denied it."); 207 break; 208 default: 209 SetError("Unexpected NewStream callback"); 210 break; 211 } 212 return NPERR_NO_ERROR; 213 } 214 215 int32 PluginGetURLTest::WriteReady(NPStream *stream) { 216 if (test_completed()) { 217 return PluginTest::WriteReady(stream); 218 } 219 220 if (!referrer_target_url_.empty()) { 221 return STREAM_CHUNK; 222 } 223 224 COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData), 225 cast_validity_check); 226 unsigned long stream_id = reinterpret_cast<unsigned long>( 227 stream->notifyData); 228 if (stream_id == BOGUS_URL_STREAM_ID) 229 SetError("Received WriteReady for BOGUS_URL"); 230 231 return STREAM_CHUNK; 232 } 233 234 int32 PluginGetURLTest::Write(NPStream *stream, int32 offset, int32 len, 235 void *buffer) { 236 if (test_completed()) { 237 return PluginTest::Write(stream, offset, len, buffer); 238 } 239 240 if (!fail_write_url_.empty()) { 241 SignalTestCompleted(); 242 return -1; 243 } 244 245 if (!referrer_target_url_.empty()) { 246 return len; 247 } 248 249 if (stream == NULL) { 250 SetError("Write got null stream"); 251 return -1; 252 } 253 if (len < 0 || len > STREAM_CHUNK) { 254 SetError("Write got bogus stream chunk size"); 255 return -1; 256 } 257 258 COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData), 259 cast_validity_check); 260 unsigned long stream_id = reinterpret_cast<unsigned long>( 261 stream->notifyData); 262 switch (stream_id) { 263 case SELF_URL_STREAM_ID: 264 self_url_.append(static_cast<char*>(buffer), len); 265 break; 266 case FETCHED_URL_STREAM_ID: 267 { 268 char read_buffer[STREAM_CHUNK]; 269 int32 bytes = 270 static_cast<int32>(fread(read_buffer, 1, len, test_file_)); 271 // Technically, fread could return fewer than len 272 // bytes. But this is not likely. 273 if (bytes != len) 274 SetError("Did not read correct bytelength from source file"); 275 if (memcmp(read_buffer, buffer, len)) 276 SetError("Content mismatch between data and source!"); 277 } 278 break; 279 case BOGUS_URL_STREAM_ID: 280 SetError("Unexpected write callback for BOGUS_URL"); 281 break; 282 default: 283 SetError("Unexpected write callback"); 284 break; 285 } 286 // Pretend that we took all the data. 287 return len; 288 } 289 290 291 NPError PluginGetURLTest::DestroyStream(NPStream *stream, NPError reason) { 292 if (test_completed()) { 293 return PluginTest::DestroyStream(stream, reason); 294 } 295 296 if (stream == NULL) { 297 SetError("NewStream got null stream"); 298 return NPERR_INVALID_PARAM; 299 } 300 301 COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData), 302 cast_validity_check); 303 304 if (expect_404_response_) { 305 if (npn_evaluate_context_) { 306 SetError("Received destroyStream in the context of NPN_Evaluate."); 307 } 308 309 SignalTestCompleted(); 310 return NPERR_NO_ERROR; 311 } 312 313 if (!referrer_target_url_.empty()) { 314 return NPERR_NO_ERROR; 315 } 316 317 unsigned long stream_id = 318 reinterpret_cast<unsigned long>(stream->notifyData); 319 switch (stream_id) { 320 case SELF_URL_STREAM_ID: 321 // don't care 322 break; 323 case FETCHED_URL_STREAM_ID: 324 { 325 char read_buffer[STREAM_CHUNK]; 326 size_t bytes = fread(read_buffer, 1, sizeof(read_buffer), test_file_); 327 if (bytes != 0) 328 SetError("Data and source mismatch on length"); 329 file_util::CloseFile(test_file_); 330 } 331 break; 332 default: 333 SetError("Unexpected NewStream callback"); 334 break; 335 } 336 return NPERR_NO_ERROR; 337 } 338 339 void PluginGetURLTest::StreamAsFile(NPStream* stream, const char* fname) { 340 if (stream == NULL) { 341 SetError("NewStream got null stream"); 342 return; 343 } 344 345 COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData), 346 cast_validity_check); 347 unsigned long stream_id = 348 reinterpret_cast<unsigned long>(stream->notifyData); 349 switch (stream_id) { 350 case SELF_URL_STREAM_ID: 351 // don't care 352 break; 353 default: 354 SetError("Unexpected NewStream callback"); 355 break; 356 } 357 } 358 359 void PluginGetURLTest::URLNotify(const char* url, NPReason reason, void* data) { 360 if (!tests_in_progress_) { 361 SetError("URLNotify received after tests completed"); 362 return; 363 } 364 365 if (!url) { 366 SetError("URLNotify received NULL url"); 367 return; 368 } 369 370 COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(data), cast_validity_check); 371 unsigned long stream_id = reinterpret_cast<unsigned long>(data); 372 switch (stream_id) { 373 case SELF_URL_STREAM_ID: 374 if (strcmp(url, SELF_URL) != 0) 375 SetError("URLNotify reported incorrect url for SELF_URL"); 376 377 // We have our stream url. Go fetch it. 378 HostFunctions()->geturlnotify(id(), self_url_.c_str(), NULL, 379 reinterpret_cast<void*>(FETCHED_URL_STREAM_ID)); 380 break; 381 case FETCHED_URL_STREAM_ID: 382 if (!url || strcmp(url, self_url_.c_str()) != 0) 383 SetError("URLNotify reported incorrect url for FETCHED_URL"); 384 tests_in_progress_--; 385 break; 386 case BOGUS_URL_STREAM_ID: 387 if (reason != NPRES_NETWORK_ERR) { 388 std::string err = "BOGUS_URL received unexpected URLNotify status: "; 389 err.append(base::IntToString(reason)); 390 SetError(err); 391 } 392 tests_in_progress_--; 393 break; 394 case REDIRECT_SRC_URL_NOTIFICATION_ID: { 395 if (!received_url_redirect_notification_) { 396 SetError("Failed to receive URLRedirect notification"); 397 } 398 tests_in_progress_--; 399 break; 400 } 401 default: 402 SetError("Unexpected NewStream callback"); 403 break; 404 } 405 406 if (tests_in_progress_ == 0) 407 SignalTestCompleted(); 408 } 409 410 void PluginGetURLTest::URLRedirectNotify(const char* url, 411 int32_t status, 412 void* notify_data) { 413 if (!base::strcasecmp(url, "http://mock.http/npapi/plugin_read_page.html")) { 414 received_url_redirect_notification_ = true; 415 // Disallow redirect notification. 416 HostFunctions()->urlredirectresponse(id(), notify_data, false); 417 } 418 } 419 420 } // namespace NPAPIClient 421