| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/test/plugin/plugin_geturl_test.h" |
| |
| #include <stdio.h> |
| |
| #include "base/basictypes.h" |
| #include "base/file_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| |
| // url for "self". The %22%22 is to make a statement for javascript to |
| // evaluate and return. |
| #define SELF_URL "javascript:window.location+\"\"" |
| |
| // The identifier for the self url stream. |
| #define SELF_URL_STREAM_ID 1 |
| |
| // The identifier for the fetched url stream. |
| #define FETCHED_URL_STREAM_ID 2 |
| |
| // url for testing GetURL with a bogus URL. |
| #define BOGUS_URL "bogoproto:///x:/asdf.xysdhffieasdf.asdhj/" |
| |
| // url for testing redirect notifications sent to plugins. |
| #define REDIRECT_SRC_URL \ |
| "http://mock.http/npapi/plugin_read_page_redirect_src.html" |
| |
| // The notification id for the redirect notification url that we will cancel. |
| #define REDIRECT_SRC_URL_NOTIFICATION_CANCEL_ID 4 |
| |
| // The notification id for the redirect notification url that we will accept. |
| #define REDIRECT_SRC_URL_NOTIFICATION_ALLOW_ID 5 |
| |
| // The identifier for the bogus url stream. |
| #define BOGUS_URL_STREAM_ID 3 |
| |
| // The maximum chunk size of stream data. |
| #define STREAM_CHUNK 197 |
| |
| namespace NPAPIClient { |
| |
| PluginGetURLTest::PluginGetURLTest(NPP id, NPNetscapeFuncs *host_functions) |
| : PluginTest(id, host_functions), |
| tests_started_(false), |
| tests_in_progress_(0), |
| test_file_(NULL), |
| expect_404_response_(false), |
| npn_evaluate_context_(false), |
| handle_url_redirects_(false), |
| received_url_redirect_cancel_notification_(false), |
| received_url_redirect_allow_notification_(false), |
| check_cookies_(false) { |
| } |
| |
| PluginGetURLTest::~PluginGetURLTest() {} |
| |
| NPError PluginGetURLTest::New(uint16 mode, int16 argc, const char* argn[], |
| const char* argv[], NPSavedData* saved) { |
| const char* page_not_found_url = GetArgValue("page_not_found_url", argc, |
| argn, argv); |
| if (page_not_found_url) { |
| page_not_found_url_ = page_not_found_url; |
| expect_404_response_ = true; |
| } |
| |
| const char* fail_write_url = GetArgValue("fail_write_url", argc, |
| argn, argv); |
| if (fail_write_url) { |
| fail_write_url_ = fail_write_url; |
| } |
| |
| const char* referrer_target_url = GetArgValue("ref_target", argc, |
| argn, argv); |
| if (referrer_target_url) { |
| referrer_target_url_ = referrer_target_url; |
| } |
| |
| if (!base::strcasecmp(GetArgValue("name", argc, argn, argv), |
| "geturlredirectnotify")) { |
| handle_url_redirects_ = true; |
| } |
| |
| NPError error = PluginTest::New(mode, argc, argn, argv, saved); |
| |
| // The above sets test_name(). |
| if (test_name() == "cookies") |
| check_cookies_ = true; |
| |
| return error; |
| } |
| |
| NPError PluginGetURLTest::SetWindow(NPWindow* pNPWindow) { |
| #if !defined(OS_MACOSX) |
| if (pNPWindow->window == NULL) |
| return NPERR_NO_ERROR; |
| #endif |
| |
| if (!tests_started_) { |
| tests_started_ = true; |
| |
| tests_in_progress_++; |
| |
| if (expect_404_response_) { |
| HostFunctions()->geturl(id(), page_not_found_url_.c_str(), NULL); |
| return NPERR_NO_ERROR; |
| } else if (!fail_write_url_.empty()) { |
| HostFunctions()->geturl(id(), fail_write_url_.c_str(), NULL); |
| return NPERR_NO_ERROR; |
| } else if (!referrer_target_url_.empty()) { |
| HostFunctions()->pushpopupsenabledstate(id(), true); |
| HostFunctions()->geturl(id(), referrer_target_url_.c_str(), "_blank"); |
| HostFunctions()->poppopupsenabledstate(id()); |
| return NPERR_NO_ERROR; |
| } else if (handle_url_redirects_) { |
| HostFunctions()->geturlnotify( |
| id(), REDIRECT_SRC_URL, NULL, |
| reinterpret_cast<void*>(REDIRECT_SRC_URL_NOTIFICATION_CANCEL_ID)); |
| return NPERR_NO_ERROR; |
| } else if (check_cookies_) { |
| HostFunctions()->geturlnotify( |
| id(), |
| "plugin_ref_target_page.html", |
| NULL, |
| reinterpret_cast<void*>(SELF_URL_STREAM_ID)); |
| return NPERR_NO_ERROR; |
| } |
| |
| std::string url = SELF_URL; |
| HostFunctions()->geturlnotify(id(), url.c_str(), NULL, |
| reinterpret_cast<void*>(SELF_URL_STREAM_ID)); |
| |
| tests_in_progress_++; |
| std::string bogus_url = BOGUS_URL; |
| HostFunctions()->geturlnotify(id(), bogus_url.c_str(), NULL, |
| reinterpret_cast<void*>(BOGUS_URL_STREAM_ID)); |
| } |
| return NPERR_NO_ERROR; |
| } |
| |
| NPError PluginGetURLTest::NewStream(NPMIMEType type, NPStream* stream, |
| NPBool seekable, uint16* stype) { |
| if (stream == NULL) { |
| SetError("NewStream got null stream"); |
| return NPERR_INVALID_PARAM; |
| } |
| |
| if (test_completed()) { |
| return PluginTest::NewStream(type, stream, seekable, stype); |
| } |
| |
| if (!referrer_target_url_.empty()) { |
| return NPERR_NO_ERROR; |
| } |
| |
| COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData), |
| cast_validity_check); |
| |
| if (expect_404_response_) { |
| NPObject *window_obj = NULL; |
| HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj); |
| if (!window_obj) { |
| SetError("Failed to get NPObject for plugin instance2"); |
| SignalTestCompleted(); |
| return NPERR_NO_ERROR; |
| } |
| |
| std::string script = "javascript:document.title=\"OK\""; |
| NPString script_string; |
| script_string.UTF8Characters = script.c_str(); |
| script_string.UTF8Length = static_cast<unsigned int>(script.length()); |
| NPVariant result_var; |
| |
| npn_evaluate_context_ = true; |
| HostFunctions()->evaluate(id(), window_obj, &script_string, &result_var); |
| npn_evaluate_context_ = false; |
| return NPERR_NO_ERROR; |
| } |
| |
| if (!fail_write_url_.empty() || check_cookies_) { |
| return NPERR_NO_ERROR; |
| } |
| |
| |
| unsigned long stream_id = reinterpret_cast<unsigned long>( |
| stream->notifyData); |
| |
| switch (stream_id) { |
| case SELF_URL_STREAM_ID: |
| break; |
| case FETCHED_URL_STREAM_ID: |
| { |
| std::string filename = self_url_; |
| if (filename.find("file:///", 0) != 0) { |
| SetError("Test expects a file-url."); |
| break; |
| } |
| |
| // TODO(evanm): use the net:: functions to convert file:// URLs to |
| // on-disk file paths. But it probably doesn't actually matter in |
| // this test. |
| |
| #if defined(OS_WIN) |
| filename = filename.substr(8); // remove "file:///" |
| // Assume an ASCII path on Windows. |
| base::FilePath path = base::FilePath(ASCIIToWide(filename)); |
| #else |
| filename = filename.substr(7); // remove "file://" |
| base::FilePath path = base::FilePath(filename); |
| #endif |
| |
| test_file_ = base::OpenFile(path, "r"); |
| if (!test_file_) { |
| SetError("Could not open source file"); |
| } |
| } |
| break; |
| case BOGUS_URL_STREAM_ID: |
| SetError("Unexpected NewStream for BOGUS_URL"); |
| break; |
| case REDIRECT_SRC_URL_NOTIFICATION_CANCEL_ID: |
| SetError("Should not redirect to URL when plugin denied it."); |
| break; |
| case REDIRECT_SRC_URL_NOTIFICATION_ALLOW_ID: |
| break; |
| default: |
| SetError("Unexpected NewStream callback"); |
| break; |
| } |
| return NPERR_NO_ERROR; |
| } |
| |
| int32 PluginGetURLTest::WriteReady(NPStream *stream) { |
| if (test_completed()) { |
| return PluginTest::WriteReady(stream); |
| } |
| |
| if (!referrer_target_url_.empty() || check_cookies_) { |
| return STREAM_CHUNK; |
| } |
| |
| COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData), |
| cast_validity_check); |
| unsigned long stream_id = reinterpret_cast<unsigned long>( |
| stream->notifyData); |
| if (stream_id == BOGUS_URL_STREAM_ID) |
| SetError("Received WriteReady for BOGUS_URL"); |
| |
| return STREAM_CHUNK; |
| } |
| |
| int32 PluginGetURLTest::Write(NPStream *stream, int32 offset, int32 len, |
| void *buffer) { |
| if (test_completed()) { |
| return PluginTest::Write(stream, offset, len, buffer); |
| } |
| |
| if (!fail_write_url_.empty()) { |
| SignalTestCompleted(); |
| return -1; |
| } |
| |
| if (!referrer_target_url_.empty() || check_cookies_) { |
| return len; |
| } |
| |
| if (stream == NULL) { |
| SetError("Write got null stream"); |
| return -1; |
| } |
| if (len < 0 || len > STREAM_CHUNK) { |
| SetError("Write got bogus stream chunk size"); |
| return -1; |
| } |
| |
| COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData), |
| cast_validity_check); |
| unsigned long stream_id = reinterpret_cast<unsigned long>( |
| stream->notifyData); |
| switch (stream_id) { |
| case SELF_URL_STREAM_ID: |
| self_url_.append(static_cast<char*>(buffer), len); |
| break; |
| case FETCHED_URL_STREAM_ID: |
| { |
| char read_buffer[STREAM_CHUNK]; |
| int32 bytes = |
| static_cast<int32>(fread(read_buffer, 1, len, test_file_)); |
| // Technically, fread could return fewer than len |
| // bytes. But this is not likely. |
| if (bytes != len) |
| SetError("Did not read correct bytelength from source file"); |
| if (memcmp(read_buffer, buffer, len)) |
| SetError("Content mismatch between data and source!"); |
| } |
| break; |
| case BOGUS_URL_STREAM_ID: |
| SetError("Unexpected write callback for BOGUS_URL"); |
| break; |
| case REDIRECT_SRC_URL_NOTIFICATION_ALLOW_ID: |
| break; |
| default: |
| SetError("Unexpected write callback"); |
| break; |
| } |
| // Pretend that we took all the data. |
| return len; |
| } |
| |
| |
| NPError PluginGetURLTest::DestroyStream(NPStream *stream, NPError reason) { |
| if (test_completed()) { |
| return PluginTest::DestroyStream(stream, reason); |
| } |
| |
| if (stream == NULL) { |
| SetError("NewStream got null stream"); |
| return NPERR_INVALID_PARAM; |
| } |
| |
| COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData), |
| cast_validity_check); |
| |
| if (expect_404_response_) { |
| if (npn_evaluate_context_) { |
| SetError("Received destroyStream in the context of NPN_Evaluate."); |
| } |
| |
| SignalTestCompleted(); |
| return NPERR_NO_ERROR; |
| } |
| |
| if (!referrer_target_url_.empty()) { |
| return NPERR_NO_ERROR; |
| } |
| |
| if (check_cookies_) { |
| SignalTestCompleted(); |
| return NPERR_NO_ERROR; |
| } |
| |
| unsigned long stream_id = |
| reinterpret_cast<unsigned long>(stream->notifyData); |
| switch (stream_id) { |
| case SELF_URL_STREAM_ID: |
| // don't care |
| break; |
| case REDIRECT_SRC_URL_NOTIFICATION_ALLOW_ID: |
| break; |
| case FETCHED_URL_STREAM_ID: |
| { |
| char read_buffer[STREAM_CHUNK]; |
| size_t bytes = fread(read_buffer, 1, sizeof(read_buffer), test_file_); |
| if (bytes != 0) |
| SetError("Data and source mismatch on length"); |
| base::CloseFile(test_file_); |
| } |
| break; |
| default: |
| SetError("Unexpected NewStream callback"); |
| break; |
| } |
| return NPERR_NO_ERROR; |
| } |
| |
| void PluginGetURLTest::StreamAsFile(NPStream* stream, const char* fname) { |
| if (stream == NULL) { |
| SetError("NewStream got null stream"); |
| return; |
| } |
| |
| COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData), |
| cast_validity_check); |
| unsigned long stream_id = |
| reinterpret_cast<unsigned long>(stream->notifyData); |
| switch (stream_id) { |
| case SELF_URL_STREAM_ID: |
| // don't care |
| break; |
| default: |
| SetError("Unexpected NewStream callback"); |
| break; |
| } |
| } |
| |
| void PluginGetURLTest::URLNotify(const char* url, NPReason reason, void* data) { |
| if (!tests_in_progress_) { |
| SetError("URLNotify received after tests completed"); |
| return; |
| } |
| |
| if (!url) { |
| SetError("URLNotify received NULL url"); |
| return; |
| } |
| |
| if (check_cookies_) |
| return; |
| |
| COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(data), cast_validity_check); |
| unsigned long stream_id = reinterpret_cast<unsigned long>(data); |
| switch (stream_id) { |
| case SELF_URL_STREAM_ID: |
| if (strcmp(url, SELF_URL) != 0) |
| SetError("URLNotify reported incorrect url for SELF_URL"); |
| |
| // We have our stream url. Go fetch it. |
| HostFunctions()->geturlnotify(id(), self_url_.c_str(), NULL, |
| reinterpret_cast<void*>(FETCHED_URL_STREAM_ID)); |
| break; |
| case FETCHED_URL_STREAM_ID: |
| if (!url || strcmp(url, self_url_.c_str()) != 0) |
| SetError("URLNotify reported incorrect url for FETCHED_URL"); |
| tests_in_progress_--; |
| break; |
| case BOGUS_URL_STREAM_ID: |
| if (reason != NPRES_NETWORK_ERR) { |
| std::string err = "BOGUS_URL received unexpected URLNotify status: "; |
| err.append(base::IntToString(reason)); |
| SetError(err); |
| } |
| tests_in_progress_--; |
| break; |
| case REDIRECT_SRC_URL_NOTIFICATION_CANCEL_ID: { |
| if (!received_url_redirect_cancel_notification_) { |
| SetError("Failed to receive URLRedirect notification for cancel"); |
| } |
| if (reason != NPRES_NETWORK_ERR) { |
| SetError("Redirected URL didn't get canceled"); |
| } |
| break; |
| } |
| case REDIRECT_SRC_URL_NOTIFICATION_ALLOW_ID: { |
| if (!received_url_redirect_allow_notification_) { |
| SetError("Failed to receive URLRedirect notification for allow"); |
| } |
| if (reason != NPRES_DONE) { |
| SetError("Redirected URL didn't complete successfully"); |
| } |
| tests_in_progress_--; |
| break; |
| } |
| default: |
| SetError("Unexpected NewStream callback"); |
| break; |
| } |
| |
| if (tests_in_progress_ == 0) |
| SignalTestCompleted(); |
| } |
| |
| void PluginGetURLTest::URLRedirectNotify(const char* url, |
| int32_t status, |
| void* notify_data) { |
| unsigned long stream_id = reinterpret_cast<unsigned long>(notify_data); |
| if (stream_id == REDIRECT_SRC_URL_NOTIFICATION_CANCEL_ID) { |
| if (!base::strcasecmp(url, |
| "http://mock.http/npapi/plugin_read_page.html")) { |
| received_url_redirect_cancel_notification_ = true; |
| // Disallow redirect notification. |
| HostFunctions()->urlredirectresponse(id(), notify_data, false); |
| |
| // Now start a request that we will allow to redirect. |
| HostFunctions()->geturlnotify( |
| id(), REDIRECT_SRC_URL, NULL, |
| reinterpret_cast<void*>(REDIRECT_SRC_URL_NOTIFICATION_ALLOW_ID)); |
| } |
| } else if (stream_id == REDIRECT_SRC_URL_NOTIFICATION_ALLOW_ID) { |
| received_url_redirect_allow_notification_ = true; |
| HostFunctions()->urlredirectresponse(id(), notify_data, true); |
| } |
| } |
| |
| } // namespace NPAPIClient |