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/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