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