• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 
PluginGetURLTest(NPP id,NPNetscapeFuncs * host_functions)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 
~PluginGetURLTest()59 PluginGetURLTest::~PluginGetURLTest() {}
60 
New(uint16 mode,int16 argc,const char * argn[],const char * argv[],NPSavedData * saved)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 
SetWindow(NPWindow * pNPWindow)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 
NewStream(NPMIMEType type,NPStream * stream,NPBool seekable,uint16 * stype)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 
WriteReady(NPStream * stream)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 
Write(NPStream * stream,int32 offset,int32 len,void * buffer)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 
DestroyStream(NPStream * stream,NPError reason)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 
StreamAsFile(NPStream * stream,const char * fname)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 
URLNotify(const char * url,NPReason reason,void * data)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 
URLRedirectNotify(const char * url,int32_t status,void * notify_data)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