| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
| 3 * Use of this source code is governed by a BSD-style license that can be | |
| 4 * found in the LICENSE file. | |
| 5 */ | |
| 6 | |
| 7 #ifdef _MSC_VER | |
| 8 // Do not warn about use of std::copy with raw pointers. | |
| 9 #pragma warning(disable : 4996) | |
| 10 #endif | |
| 11 | |
| 12 #include "native_client/src/trusted/plugin/plugin.h" | |
| 13 | |
| 14 #include <assert.h> | |
| 15 #include <fcntl.h> | |
| 16 #include <stdarg.h> | |
| 17 #include <stdio.h> | |
| 18 #include <stdlib.h> | |
| 19 #include <string.h> | |
| 20 | |
| 21 #include <sys/types.h> | |
| 22 #include <sys/stat.h> | |
| 23 | |
| 24 #include <algorithm> | |
| 25 #include <deque> | |
| 26 #include <string> | |
| 27 #include <vector> | |
| 28 | |
| 29 #include "native_client/src/include/nacl_base.h" | |
| 30 #include "native_client/src/include/nacl_macros.h" | |
| 31 #include "native_client/src/include/nacl_scoped_ptr.h" | |
| 32 #include "native_client/src/include/nacl_string.h" | |
| 33 #include "native_client/src/include/portability.h" | |
| 34 #include "native_client/src/include/portability_io.h" | |
| 35 #include "native_client/src/include/portability_string.h" | |
| 36 #include "native_client/src/shared/platform/nacl_check.h" | |
| 37 #include "native_client/src/shared/platform/nacl_time.h" | |
| 38 #include "native_client/src/shared/ppapi_proxy/browser_ppp.h" | |
| 39 #include "native_client/src/trusted/desc/nacl_desc_base.h" | |
| 40 #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h" | |
| 41 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" | |
| 42 #include "native_client/src/trusted/handle_pass/browser_handle.h" | |
| 43 #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h" | |
| 44 #include "native_client/src/trusted/plugin/browser_interface.h" | |
| 45 #include "native_client/src/trusted/plugin/desc_based_handle.h" | |
| 46 #include "native_client/src/trusted/plugin/manifest.h" | |
| 47 #include "native_client/src/trusted/plugin/nacl_subprocess.h" | |
| 48 #include "native_client/src/trusted/plugin/nexe_arch.h" | |
| 49 #include "native_client/src/trusted/plugin/plugin_error.h" | |
| 50 #include "native_client/src/trusted/plugin/scriptable_handle.h" | |
| 51 #include "native_client/src/trusted/plugin/service_runtime.h" | |
| 52 #include "native_client/src/trusted/plugin/string_encoding.h" | |
| 53 #include "native_client/src/trusted/plugin/utility.h" | |
| 54 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h" | |
| 55 #include "native_client/src/trusted/service_runtime/nacl_error_code.h" | |
| 56 | |
| 57 #include "ppapi/c/dev/ppp_find_dev.h" | |
| 58 #include "ppapi/c/dev/ppp_printing_dev.h" | |
| 59 #include "ppapi/c/dev/ppp_scrollbar_dev.h" | |
| 60 #include "ppapi/c/dev/ppp_selection_dev.h" | |
| 61 #include "ppapi/c/dev/ppp_widget_dev.h" | |
| 62 #include "ppapi/c/dev/ppp_zoom_dev.h" | |
| 63 #include "ppapi/c/pp_errors.h" | |
| 64 #include "ppapi/c/ppp_input_event.h" | |
| 65 #include "ppapi/c/ppp_instance.h" | |
| 66 #include "ppapi/c/private/ppb_uma_private.h" | |
| 67 #include "ppapi/cpp/dev/find_dev.h" | |
| 68 #include "ppapi/cpp/dev/printing_dev.h" | |
| 69 #include "ppapi/cpp/dev/scrollbar_dev.h" | |
| 70 #include "ppapi/cpp/dev/selection_dev.h" | |
| 71 #include "ppapi/cpp/dev/url_util_dev.h" | |
| 72 #include "ppapi/cpp/dev/widget_client_dev.h" | |
| 73 #include "ppapi/cpp/dev/zoom_dev.h" | |
| 74 #include "ppapi/cpp/image_data.h" | |
| 75 #include "ppapi/cpp/input_event.h" | |
| 76 #include "ppapi/cpp/module.h" | |
| 77 #include "ppapi/cpp/rect.h" | |
| 78 | |
| 79 using ppapi_proxy::BrowserPpp; | |
| 80 | |
| 81 namespace plugin { | |
| 82 | |
| 83 namespace { | |
| 84 | |
| 85 bool GetReadyStateProperty(void* obj, SrpcParams* params) { | |
| 86 Plugin* plugin = static_cast<Plugin*>(obj); | |
| 87 params->outs()[0]->u.ival = plugin->nacl_ready_state(); | |
| 88 return true; | |
| 89 } | |
| 90 | |
| 91 const char* const kTypeAttribute = "type"; | |
| 92 // The "src" attribute of the <embed> tag. The value is expected to be either | |
| 93 // a URL or URI pointing to the manifest file (which is expected to contain | |
| 94 // JSON matching ISAs with .nexe URLs). | |
| 95 const char* const kSrcManifestAttribute = "src"; | |
| 96 // The "nacl" attribute of the <embed> tag. We use the value of this attribute | |
| 97 // to find the manifest file when NaCl is registered as a plug-in for another | |
| 98 // MIME type because the "src" attribute is used to supply us with the resource | |
| 99 // of that MIME type that we're supposed to display. | |
| 100 const char* const kNaClManifestAttribute = "nacl"; | |
| 101 // This is a pretty arbitrary limit on the byte size of the NaCl manfest file. | |
| 102 // Note that the resulting string object has to have at least one byte extra | |
| 103 // for the null termination character. | |
| 104 const size_t kNaClManifestMaxFileBytes = 1024 * 1024; | |
| 105 | |
| 106 // URL schemes that we treat in special ways. | |
| 107 const char* const kChromeExtensionUriScheme = "chrome-extension"; | |
| 108 const char* const kDataUriScheme = "data"; | |
| 109 | |
| 110 // The key used to find the dictionary nexe URLs in the manifest file. | |
| 111 const char* const kNexesKey = "nexes"; | |
| 112 | |
| 113 bool GetLastError(void* obj, SrpcParams* params) { | |
| 114 NaClSrpcArg** outs = params->outs(); | |
| 115 PLUGIN_PRINTF(("GetLastError (obj=%p)\n", obj)); | |
| 116 | |
| 117 Plugin* plugin = static_cast<Plugin*>(obj); | |
| 118 outs[0]->arrays.str = strdup(plugin->last_error_string().c_str()); | |
| 119 return true; | |
| 120 } | |
| 121 | |
| 122 // Up to 20 seconds | |
| 123 const int64_t kTimeSmallMin = 1; // in ms | |
| 124 const int64_t kTimeSmallMax = 20000; // in ms | |
| 125 const uint32_t kTimeSmallBuckets = 100; | |
| 126 | |
| 127 // Up to 3 minutes, 20 seconds | |
| 128 const int64_t kTimeMediumMin = 10; // in ms | |
| 129 const int64_t kTimeMediumMax = 200000; // in ms | |
| 130 const uint32_t kTimeMediumBuckets = 100; | |
| 131 | |
| 132 // Up to 33 minutes. | |
| 133 const int64_t kTimeLargeMin = 100; // in ms | |
| 134 const int64_t kTimeLargeMax = 2000000; // in ms | |
| 135 const uint32_t kTimeLargeBuckets = 100; | |
| 136 | |
| 137 const int64_t kSizeKBMin = 1; | |
| 138 const int64_t kSizeKBMax = 512*1024; // very large .nexe | |
| 139 const uint32_t kSizeKBBuckets = 100; | |
| 140 | |
| 141 const PPB_UMA_Private* GetUMAInterface() { | |
| 142 pp::Module *module = pp::Module::Get(); | |
| 143 CHECK(module); | |
| 144 return static_cast<const PPB_UMA_Private*>( | |
| 145 module->GetBrowserInterface(PPB_UMA_PRIVATE_INTERFACE)); | |
| 146 } | |
| 147 | |
| 148 void HistogramTimeSmall(const std::string& name, int64_t ms) { | |
| 149 if (ms < 0) return; | |
| 150 | |
| 151 const PPB_UMA_Private* ptr = GetUMAInterface(); | |
| 152 if (ptr == NULL) return; | |
| 153 | |
| 154 ptr->HistogramCustomTimes(pp::Var(name).pp_var(), | |
| 155 ms, | |
| 156 kTimeSmallMin, kTimeSmallMax, | |
| 157 kTimeSmallBuckets); | |
| 158 } | |
| 159 | |
| 160 void HistogramTimeMedium(const std::string& name, int64_t ms) { | |
| 161 if (ms < 0) return; | |
| 162 | |
| 163 const PPB_UMA_Private* ptr = GetUMAInterface(); | |
| 164 if (ptr == NULL) return; | |
| 165 | |
| 166 ptr->HistogramCustomTimes(pp::Var(name).pp_var(), | |
| 167 ms, | |
| 168 kTimeMediumMin, kTimeMediumMax, | |
| 169 kTimeMediumBuckets); | |
| 170 } | |
| 171 | |
| 172 void HistogramTimeLarge(const std::string& name, int64_t ms) { | |
| 173 if (ms < 0) return; | |
| 174 | |
| 175 const PPB_UMA_Private* ptr = GetUMAInterface(); | |
| 176 if (ptr == NULL) return; | |
| 177 | |
| 178 ptr->HistogramCustomTimes(pp::Var(name).pp_var(), | |
| 179 ms, | |
| 180 kTimeLargeMin, kTimeLargeMax, | |
| 181 kTimeLargeBuckets); | |
| 182 } | |
| 183 | |
| 184 void HistogramSizeKB(const std::string& name, int32_t sample) { | |
| 185 if (sample < 0) return; | |
| 186 | |
| 187 const PPB_UMA_Private* ptr = GetUMAInterface(); | |
| 188 if (ptr == NULL) return; | |
| 189 | |
| 190 ptr->HistogramCustomCounts(pp::Var(name).pp_var(), | |
| 191 sample, | |
| 192 kSizeKBMin, kSizeKBMax, | |
| 193 kSizeKBBuckets); | |
| 194 } | |
| 195 | |
| 196 void HistogramEnumerate(const std::string& name, int sample, int maximum, | |
| 197 int out_of_range_replacement) { | |
| 198 if (sample < 0 || sample >= maximum) { | |
| 199 if (out_of_range_replacement < 0) | |
| 200 // No replacement for bad input, abort. | |
| 201 return; | |
| 202 else | |
| 203 // Use a specific value to signal a bad input. | |
| 204 sample = out_of_range_replacement; | |
| 205 } | |
| 206 const PPB_UMA_Private* ptr = GetUMAInterface(); | |
| 207 if (ptr == NULL) return; | |
| 208 ptr->HistogramEnumeration(pp::Var(name).pp_var(), sample, maximum); | |
| 209 } | |
| 210 | |
| 211 void HistogramEnumerateOsArch(const std::string& sandbox_isa) { | |
| 212 enum NaClOSArch { | |
| 213 kNaClLinux32 = 0, | |
| 214 kNaClLinux64, | |
| 215 kNaClLinuxArm, | |
| 216 kNaClMac32, | |
| 217 kNaClMac64, | |
| 218 kNaClMacArm, | |
| 219 kNaClWin32, | |
| 220 kNaClWin64, | |
| 221 kNaClWinArm, | |
| 222 kNaClOSArchMax | |
| 223 }; | |
| 224 | |
| 225 NaClOSArch os_arch = kNaClOSArchMax; | |
| 226 #if NACL_LINUX | |
| 227 os_arch = kNaClLinux32; | |
| 228 #elif NACL_OSX | |
| 229 os_arch = kNaClMac32; | |
| 230 #elif NACL_WINDOWS | |
| 231 os_arch = kNaClWin32; | |
| 232 #endif | |
| 233 | |
| 234 if (sandbox_isa == "x86-64") | |
| 235 os_arch = static_cast<NaClOSArch>(os_arch + 1); | |
| 236 if (sandbox_isa == "arm") | |
| 237 os_arch = static_cast<NaClOSArch>(os_arch + 2); | |
| 238 | |
| 239 HistogramEnumerate("NaCl.Client.OSArch", os_arch, kNaClOSArchMax, -1); | |
| 240 } | |
| 241 | |
| 242 void HistogramEnumerateLoadStatus(PluginErrorCode error_code) { | |
| 243 HistogramEnumerate("NaCl.LoadStatus.Plugin", error_code, ERROR_MAX, | |
| 244 ERROR_UNKNOWN); | |
| 245 } | |
| 246 | |
| 247 void HistogramEnumerateSelLdrLoadStatus(NaClErrorCode error_code) { | |
| 248 HistogramEnumerate("NaCl.LoadStatus.SelLdr", error_code, NACL_ERROR_CODE_MAX, | |
| 249 LOAD_STATUS_UNKNOWN); | |
| 250 } | |
| 251 | |
| 252 void HistogramEnumerateManifestIsDataURI(bool is_data_uri) { | |
| 253 HistogramEnumerate("NaCl.Manifest.IsDataURI", is_data_uri, 2, -1); | |
| 254 } | |
| 255 | |
| 256 // Derive a class from pp::Find_Dev to forward PPP_Find_Dev calls to | |
| 257 // the plugin. | |
| 258 class FindAdapter : public pp::Find_Dev { | |
| 259 public: | |
| 260 explicit FindAdapter(Plugin* plugin) | |
| 261 : pp::Find_Dev(plugin), | |
| 262 plugin_(plugin) { | |
| 263 BrowserPpp* proxy = plugin_->ppapi_proxy(); | |
| 264 CHECK(proxy != NULL); | |
| 265 ppp_find_ = static_cast<const PPP_Find_Dev*>( | |
| 266 proxy->GetPluginInterface(PPP_FIND_DEV_INTERFACE)); | |
| 267 } | |
| 268 | |
| 269 bool StartFind(const std::string& text, bool case_sensitive) { | |
| 270 if (ppp_find_ != NULL) { | |
| 271 PP_Bool pp_success = | |
| 272 ppp_find_->StartFind(plugin_->pp_instance(), | |
| 273 text.c_str(), | |
| 274 PP_FromBool(case_sensitive)); | |
| 275 return pp_success == PP_TRUE; | |
| 276 } | |
| 277 return false; | |
| 278 } | |
| 279 | |
| 280 void SelectFindResult(bool forward) { | |
| 281 if (ppp_find_ != NULL) { | |
| 282 ppp_find_->SelectFindResult(plugin_->pp_instance(), | |
| 283 PP_FromBool(forward)); | |
| 284 } | |
| 285 } | |
| 286 | |
| 287 void StopFind() { | |
| 288 if (ppp_find_ != NULL) | |
| 289 ppp_find_->StopFind(plugin_->pp_instance()); | |
| 290 } | |
| 291 | |
| 292 private: | |
| 293 Plugin* plugin_; | |
| 294 const PPP_Find_Dev* ppp_find_; | |
| 295 | |
| 296 NACL_DISALLOW_COPY_AND_ASSIGN(FindAdapter); | |
| 297 }; | |
| 298 | |
| 299 | |
| 300 // Derive a class from pp::Printing_Dev to forward PPP_Printing_Dev calls to | |
| 301 // the plugin. | |
| 302 class PrintingAdapter : public pp::Printing_Dev { | |
| 303 public: | |
| 304 explicit PrintingAdapter(Plugin* plugin) | |
| 305 : pp::Printing_Dev(plugin), | |
| 306 plugin_(plugin) { | |
| 307 BrowserPpp* proxy = plugin_->ppapi_proxy(); | |
| 308 CHECK(proxy != NULL); | |
| 309 ppp_printing_ = static_cast<const PPP_Printing_Dev*>( | |
| 310 proxy->GetPluginInterface(PPP_PRINTING_DEV_INTERFACE)); | |
| 311 } | |
| 312 | |
| 313 PP_PrintOutputFormat_Dev* | |
| 314 QuerySupportedPrintOutputFormats(uint32_t* format_count) { | |
| 315 if (ppp_printing_ != NULL) { | |
| 316 return ppp_printing_->QuerySupportedFormats(plugin_->pp_instance(), | |
| 317 format_count); | |
| 318 } | |
| 319 *format_count = 0; | |
| 320 return NULL; | |
| 321 } | |
| 322 | |
| 323 int32_t PrintBegin(const PP_PrintSettings_Dev& print_settings) { | |
| 324 if (ppp_printing_ != NULL) { | |
| 325 return ppp_printing_->Begin(plugin_->pp_instance(), &print_settings); | |
| 326 } | |
| 327 return 0; | |
| 328 } | |
| 329 | |
| 330 pp::Resource PrintPages(const PP_PrintPageNumberRange_Dev* page_ranges, | |
| 331 uint32_t page_range_count) { | |
| 332 if (ppp_printing_ != NULL) { | |
| 333 PP_Resource image_data = ppp_printing_->PrintPages(plugin_->pp_instance(), | |
| 334 page_ranges, | |
| 335 page_range_count); | |
| 336 return pp::ImageData(pp::ImageData::PassRef(), image_data); | |
| 337 } | |
| 338 return pp::Resource(); | |
| 339 } | |
| 340 | |
| 341 void PrintEnd() { | |
| 342 if (ppp_printing_ != NULL) | |
| 343 ppp_printing_->End(plugin_->pp_instance()); | |
| 344 } | |
| 345 | |
| 346 private: | |
| 347 Plugin* plugin_; | |
| 348 const PPP_Printing_Dev* ppp_printing_; | |
| 349 | |
| 350 NACL_DISALLOW_COPY_AND_ASSIGN(PrintingAdapter); | |
| 351 }; | |
| 352 | |
| 353 | |
| 354 // Derive a class from pp::Selection_Dev to forward PPP_Selection_Dev calls to | |
| 355 // the plugin. | |
| 356 class SelectionAdapter : public pp::Selection_Dev { | |
| 357 public: | |
| 358 explicit SelectionAdapter(Plugin* plugin) | |
| 359 : pp::Selection_Dev(plugin), | |
| 360 plugin_(plugin) { | |
| 361 BrowserPpp* proxy = plugin_->ppapi_proxy(); | |
| 362 CHECK(proxy != NULL); | |
| 363 ppp_selection_ = static_cast<const PPP_Selection_Dev*>( | |
| 364 proxy->GetPluginInterface(PPP_SELECTION_DEV_INTERFACE)); | |
| 365 } | |
| 366 | |
| 367 pp::Var GetSelectedText(bool html) { | |
| 368 if (ppp_selection_ != NULL) { | |
| 369 PP_Var var = ppp_selection_->GetSelectedText(plugin_->pp_instance(), | |
| 370 PP_FromBool(html)); | |
| 371 return pp::Var(pp::Var::PassRef(), var); | |
| 372 } | |
| 373 return pp::Var(); | |
| 374 } | |
| 375 | |
| 376 private: | |
| 377 Plugin* plugin_; | |
| 378 const PPP_Selection_Dev* ppp_selection_; | |
| 379 | |
| 380 NACL_DISALLOW_COPY_AND_ASSIGN(SelectionAdapter); | |
| 381 }; | |
| 382 | |
| 383 | |
| 384 // Derive a class from pp::WidgetClient_Dev to forward PPP_Widget_Dev | |
| 385 // and PPP_Scrollbar_Dev calls to the plugin. | |
| 386 class WidgetClientAdapter : public pp::WidgetClient_Dev { | |
| 387 public: | |
| 388 explicit WidgetClientAdapter(Plugin* plugin) | |
| 389 : pp::WidgetClient_Dev(plugin), | |
| 390 plugin_(plugin) { | |
| 391 BrowserPpp* proxy = plugin_->ppapi_proxy(); | |
| 392 CHECK(proxy != NULL); | |
| 393 ppp_widget_ = static_cast<const PPP_Widget_Dev*>( | |
| 394 proxy->GetPluginInterface(PPP_WIDGET_DEV_INTERFACE)); | |
| 395 ppp_scrollbar_ = static_cast<const PPP_Scrollbar_Dev*>( | |
| 396 proxy->GetPluginInterface(PPP_SCROLLBAR_DEV_INTERFACE)); | |
| 397 } | |
| 398 | |
| 399 void InvalidateWidget(pp::Widget_Dev widget, const pp::Rect& dirty_rect) { | |
| 400 if (ppp_widget_ != NULL) { | |
| 401 ppp_widget_->Invalidate(plugin_->pp_instance(), | |
| 402 widget.pp_resource(), | |
| 403 &dirty_rect.pp_rect()); | |
| 404 } | |
| 405 } | |
| 406 | |
| 407 void ScrollbarValueChanged(pp::Scrollbar_Dev scrollbar, uint32_t value) { | |
| 408 if (ppp_scrollbar_ != NULL) { | |
| 409 ppp_scrollbar_->ValueChanged(plugin_->pp_instance(), | |
| 410 scrollbar.pp_resource(), | |
| 411 value); | |
| 412 } | |
| 413 } | |
| 414 | |
| 415 void ScrollbarOverlayChanged(pp::Scrollbar_Dev scrollbar, bool overlay) { | |
| 416 if (ppp_scrollbar_ != NULL) { | |
| 417 ppp_scrollbar_->OverlayChanged(plugin_->pp_instance(), | |
| 418 scrollbar.pp_resource(), | |
| 419 PP_FromBool(overlay)); | |
| 420 } | |
| 421 } | |
| 422 | |
| 423 private: | |
| 424 Plugin* plugin_; | |
| 425 const PPP_Widget_Dev* ppp_widget_; | |
| 426 const PPP_Scrollbar_Dev* ppp_scrollbar_; | |
| 427 | |
| 428 NACL_DISALLOW_COPY_AND_ASSIGN(WidgetClientAdapter); | |
| 429 }; | |
| 430 | |
| 431 | |
| 432 // Derive a class from pp::Zoom_Dev to forward PPP_Zoom_Dev calls to | |
| 433 // the plugin. | |
| 434 class ZoomAdapter : public pp::Zoom_Dev { | |
| 435 public: | |
| 436 explicit ZoomAdapter(Plugin* plugin) | |
| 437 : pp::Zoom_Dev(plugin), | |
| 438 plugin_(plugin) { | |
| 439 BrowserPpp* proxy = plugin_->ppapi_proxy(); | |
| 440 CHECK(proxy != NULL); | |
| 441 ppp_zoom_ = static_cast<const PPP_Zoom_Dev*>( | |
| 442 proxy->GetPluginInterface(PPP_ZOOM_DEV_INTERFACE)); | |
| 443 } | |
| 444 | |
| 445 void Zoom(double factor, bool text_only) { | |
| 446 if (ppp_zoom_ != NULL) { | |
| 447 ppp_zoom_->Zoom(plugin_->pp_instance(), | |
| 448 factor, | |
| 449 PP_FromBool(text_only)); | |
| 450 } | |
| 451 } | |
| 452 | |
| 453 private: | |
| 454 Plugin* plugin_; | |
| 455 const PPP_Zoom_Dev* ppp_zoom_; | |
| 456 | |
| 457 NACL_DISALLOW_COPY_AND_ASSIGN(ZoomAdapter); | |
| 458 }; | |
| 459 | |
| 460 } // namespace | |
| 461 | |
| 462 bool Plugin::ExperimentalJavaScriptApisAreEnabled() { | |
| 463 return getenv("NACL_ENABLE_EXPERIMENTAL_JAVASCRIPT_APIS") != NULL; | |
| 464 } | |
| 465 | |
| 466 static int const kAbiHeaderBuffer = 256; // must be at least EI_ABIVERSION + 1 | |
| 467 | |
| 468 void Plugin::LoadMethods() { | |
| 469 PLUGIN_PRINTF(("Plugin::LoadMethods ()\n")); | |
| 470 // Properties implemented by Plugin. | |
| 471 AddPropertyGet(GetReadyStateProperty, "readyState", "i"); | |
| 472 } | |
| 473 | |
| 474 bool Plugin::HasMethod(uintptr_t method_id, CallType call_type) { | |
| 475 PLUGIN_PRINTF(("Plugin::HasMethod (method_id=%x) = ", | |
| 476 static_cast<int>(method_id))); | |
| 477 if (GetMethodInfo(method_id, call_type)) { | |
| 478 PLUGIN_PRINTF(("true\n")); | |
| 479 return true; | |
| 480 } | |
| 481 if (!ExperimentalJavaScriptApisAreEnabled()) { | |
| 482 PLUGIN_PRINTF(("false\n")); | |
| 483 return false; | |
| 484 } | |
| 485 if (call_type != METHOD_CALL) { | |
| 486 // SRPC nexes can only export methods. | |
| 487 PLUGIN_PRINTF(("false\n")); | |
| 488 return false; | |
| 489 } | |
| 490 bool has_method = main_subprocess_.HasMethod(method_id); | |
| 491 PLUGIN_PRINTF(("%s\n", (has_method ? "true" : "false"))); | |
| 492 return has_method; | |
| 493 } | |
| 494 | |
| 495 bool Plugin::InitParams(uintptr_t method_id, | |
| 496 CallType call_type, | |
| 497 SrpcParams* params) { | |
| 498 MethodInfo* method_info = GetMethodInfo(method_id, call_type); | |
| 499 PLUGIN_PRINTF(("Plugin::InitParams (id=%"NACL_PRIxPTR", method_info=%p)\n", | |
| 500 method_id, method_info)); | |
| 501 if (NULL != method_info) { | |
| 502 return params->Init(method_info->ins(), method_info->outs()); | |
| 503 } | |
| 504 if (!ExperimentalJavaScriptApisAreEnabled()) { | |
| 505 return false; | |
| 506 } | |
| 507 if (call_type != METHOD_CALL) { | |
| 508 // SRPC nexes can only export methods. | |
| 509 return false; | |
| 510 } | |
| 511 return main_subprocess_.InitParams(method_id, params); | |
| 512 } | |
| 513 | |
| 514 bool Plugin::Invoke(uintptr_t method_id, | |
| 515 CallType call_type, | |
| 516 SrpcParams* params) { | |
| 517 MethodInfo* method_info = GetMethodInfo(method_id, call_type); | |
| 518 | |
| 519 if (NULL != method_info && NULL != method_info->function_ptr()) { | |
| 520 return method_info->function_ptr()(static_cast<void*>(this), params); | |
| 521 } | |
| 522 if (!ExperimentalJavaScriptApisAreEnabled()) { | |
| 523 return false; | |
| 524 } | |
| 525 if (call_type != METHOD_CALL) { | |
| 526 // SRPC nexes can only export methods. | |
| 527 return false; | |
| 528 } | |
| 529 return main_subprocess_.Invoke(method_id, params); | |
| 530 } | |
| 531 | |
| 532 bool Plugin::Init(BrowserInterface* browser_interface, | |
| 533 int argc, | |
| 534 char* argn[], | |
| 535 char* argv[]) { | |
| 536 PLUGIN_PRINTF(("Plugin::Init (instance=%p)\n", static_cast<void*>(this))); | |
| 537 | |
| 538 browser_interface_ = browser_interface; | |
| 539 // Remember the embed/object argn/argv pairs. | |
| 540 argn_ = new(std::nothrow) char*[argc]; | |
| 541 argv_ = new(std::nothrow) char*[argc]; | |
| 542 argc_ = 0; | |
| 543 for (int i = 0; i < argc; ++i) { | |
| 544 if (NULL != argn_ && NULL != argv_) { | |
| 545 argn_[argc_] = strdup(argn[i]); | |
| 546 argv_[argc_] = strdup(argv[i]); | |
| 547 if (NULL == argn_[argc_] || NULL == argv_[argc_]) { | |
| 548 // Give up on passing arguments. | |
| 549 free(argn_[argc_]); | |
| 550 free(argv_[argc_]); | |
| 551 continue; | |
| 552 } | |
| 553 ++argc_; | |
| 554 } | |
| 555 } | |
| 556 // TODO(sehr): this leaks strings if there is a subsequent failure. | |
| 557 | |
| 558 // Set up the factory used to produce DescWrappers. | |
| 559 wrapper_factory_ = new nacl::DescWrapperFactory(); | |
| 560 if (NULL == wrapper_factory_) { | |
| 561 return false; | |
| 562 } | |
| 563 PLUGIN_PRINTF(("Plugin::Init (wrapper_factory=%p)\n", | |
| 564 static_cast<void*>(wrapper_factory_))); | |
| 565 | |
| 566 // Set up the scriptable methods for the plugin. | |
| 567 LoadMethods(); | |
| 568 | |
| 569 PLUGIN_PRINTF(("Plugin::Init (return 1)\n")); | |
| 570 // Return success. | |
| 571 return true; | |
| 572 } | |
| 573 | |
| 574 void Plugin::ShutDownSubprocesses() { | |
| 575 PLUGIN_PRINTF(("Plugin::ShutDownSubprocesses (this=%p)\n", | |
| 576 static_cast<void*>(this))); | |
| 577 PLUGIN_PRINTF(("Plugin::ShutDownSubprocesses (%s)\n", | |
| 578 main_subprocess_.detailed_description().c_str())); | |
| 579 | |
| 580 // Shutdown service runtime. This must be done before all other calls so | |
| 581 // they don't block forever when waiting for the upcall thread to exit. | |
| 582 main_subprocess_.Shutdown(); | |
| 583 for (size_t i = 0; i < nacl_subprocesses_.size(); ++i) { | |
| 584 PLUGIN_PRINTF(("Plugin::ShutDownSubprocesses (%s)\n", | |
| 585 nacl_subprocesses_[i]->detailed_description().c_str())); | |
| 586 delete nacl_subprocesses_[i]; | |
| 587 } | |
| 588 nacl_subprocesses_.clear(); | |
| 589 | |
| 590 PLUGIN_PRINTF(("Plugin::ShutDownSubprocess (this=%p, return)\n", | |
| 591 static_cast<void*>(this))); | |
| 592 } | |
| 593 | |
| 594 bool Plugin::LoadNaClModuleCommon(nacl::DescWrapper* wrapper, | |
| 595 NaClSubprocess* subprocess, | |
| 596 ErrorInfo* error_info, | |
| 597 pp::CompletionCallback init_done_cb) { | |
| 598 ServiceRuntime* new_service_runtime = new(std::nothrow) ServiceRuntime( | |
| 599 this, | |
| 600 init_done_cb); | |
| 601 subprocess->set_service_runtime(new_service_runtime); | |
| 602 PLUGIN_PRINTF(("Plugin::LoadNaClModuleCommon (service_runtime=%p)\n", | |
| 603 static_cast<void*>(new_service_runtime))); | |
| 604 if (NULL == new_service_runtime) { | |
| 605 error_info->SetReport(ERROR_SEL_LDR_INIT, | |
| 606 "sel_ldr init failure " + subprocess->description()); | |
| 607 return false; | |
| 608 } | |
| 609 | |
| 610 bool service_runtime_started = | |
| 611 new_service_runtime->Start(wrapper, error_info); | |
| 612 PLUGIN_PRINTF(("Plugin::LoadNaClModuleCommon (service_runtime_started=%d)\n", | |
| 613 service_runtime_started)); | |
| 614 if (!service_runtime_started) { | |
| 615 return false; | |
| 616 } | |
| 617 return true; | |
| 618 } | |
| 619 | |
| 620 bool Plugin::StartSrpcServicesCommon(NaClSubprocess* subprocess, | |
| 621 ErrorInfo* error_info) { | |
| 622 if (!subprocess->StartSrpcServices()) { | |
| 623 error_info->SetReport(ERROR_SRPC_CONNECTION_FAIL, | |
| 624 "SRPC connection failure for " + | |
| 625 subprocess->description()); | |
| 626 return false; | |
| 627 } | |
| 628 PLUGIN_PRINTF(("Plugin::StartSrpcServicesCommon (established srpc_client " | |
| 629 "%p)\n", | |
| 630 static_cast<void*>(subprocess->srpc_client()))); | |
| 631 return true; | |
| 632 } | |
| 633 | |
| 634 bool Plugin::StartSrpcServices(NaClSubprocess* subprocess, | |
| 635 ErrorInfo* error_info) { | |
| 636 if (!StartSrpcServicesCommon(subprocess, error_info)) { | |
| 637 return false; | |
| 638 } | |
| 639 // TODO(jvoung): This next bit is likely not needed... | |
| 640 // If StartSrpcServices is only in the JS API that is just for SRPC nexes | |
| 641 // (namely __startSrpcServices), then attempts to start the JS proxy | |
| 642 // will fail anyway? | |
| 643 // If that is the case, by removing the following line, | |
| 644 // the StartSrpcServices == StartSrpcServicesCommon. | |
| 645 // We still need this function though, to launch helper SRPC nexes within | |
| 646 // the plugin. | |
| 647 return StartJSObjectProxy(subprocess, error_info); | |
| 648 } | |
| 649 | |
| 650 bool Plugin::StartJSObjectProxy(NaClSubprocess* subprocess, | |
| 651 ErrorInfo* error_info) { | |
| 652 if (!subprocess->StartJSObjectProxy(this, error_info)) { | |
| 653 // TODO(sehr,polina): rename the function and env var | |
| 654 // to ExperimentalJavaScriptApisAreEnabled. | |
| 655 if (error_info->error_code() == ERROR_START_PROXY_CHECK_PPP && | |
| 656 ExperimentalJavaScriptApisAreEnabled()) { | |
| 657 // It is not an error for the proxy to fail to find PPP methods if | |
| 658 // experimental APIs are enabled. This means we have an SRPC nexe. | |
| 659 error_info->Reset(); | |
| 660 } else { | |
| 661 return false; | |
| 662 } | |
| 663 } | |
| 664 return true; | |
| 665 } | |
| 666 | |
| 667 bool Plugin::LoadNaClModule(nacl::DescWrapper* wrapper, | |
| 668 ErrorInfo* error_info, | |
| 669 pp::CompletionCallback init_done_cb) { | |
| 670 // Before forking a new sel_ldr process, ensure that we do not leak | |
| 671 // the ServiceRuntime object for an existing subprocess, and that any | |
| 672 // associated listener threads do not go unjoined because if they | |
| 673 // outlive the Plugin object, they will not be memory safe. | |
| 674 ShutDownSubprocesses(); | |
| 675 if (!(LoadNaClModuleCommon(wrapper, &main_subprocess_, error_info, | |
| 676 init_done_cb))) { | |
| 677 return false; | |
| 678 } | |
| 679 PLUGIN_PRINTF(("Plugin::LoadNaClModule (%s)\n", | |
| 680 main_subprocess_.detailed_description().c_str())); | |
| 681 return true; | |
| 682 } | |
| 683 | |
| 684 bool Plugin::LoadNaClModuleContinuationIntern(ErrorInfo* error_info) { | |
| 685 if (!(StartSrpcServicesCommon(&main_subprocess_, error_info) | |
| 686 && StartJSObjectProxy(&main_subprocess_, error_info))) { | |
| 687 return false; | |
| 688 } | |
| 689 PLUGIN_PRINTF(("Plugin::LoadNaClModule (%s)\n", | |
| 690 main_subprocess_.detailed_description().c_str())); | |
| 691 return true; | |
| 692 } | |
| 693 | |
| 694 NaClSubprocessId Plugin::LoadHelperNaClModule(nacl::DescWrapper* wrapper, | |
| 695 ErrorInfo* error_info) { | |
| 696 NaClSubprocessId next_id = next_nacl_subprocess_id(); | |
| 697 nacl::scoped_ptr<NaClSubprocess> nacl_subprocess( | |
| 698 new(std::nothrow) NaClSubprocess(next_id, NULL, NULL)); | |
| 699 if (NULL == nacl_subprocess.get()) { | |
| 700 error_info->SetReport(ERROR_SEL_LDR_INIT, | |
| 701 "unable to allocate helper subprocess."); | |
| 702 return kInvalidNaClSubprocessId; | |
| 703 } | |
| 704 | |
| 705 if (!(LoadNaClModuleCommon(wrapper, nacl_subprocess.get(), error_info, | |
| 706 pp::BlockUntilComplete()) | |
| 707 // We need not wait for the init_done callback. We can block | |
| 708 // here in StartSrpcServicesCommon, since helper NaCl modules | |
| 709 // are spawned from a private thread. | |
| 710 // | |
| 711 // NB: More refactoring might be needed, however, if helper | |
| 712 // NaCl modules have their own manifest. Currently the | |
| 713 // manifest is a per-plugin-instance object, not a per | |
| 714 // NaClSubprocess object. | |
| 715 && StartSrpcServicesCommon(nacl_subprocess.get(), error_info))) { | |
| 716 return kInvalidNaClSubprocessId; | |
| 717 } | |
| 718 | |
| 719 PLUGIN_PRINTF(("Plugin::LoadHelperNaClModule (%s)\n", | |
| 720 nacl_subprocess.get()->detailed_description().c_str())); | |
| 721 | |
| 722 nacl_subprocesses_.push_back(nacl_subprocess.release()); | |
| 723 return next_id; | |
| 724 } | |
| 725 | |
| 726 char* Plugin::LookupArgument(const char* key) { | |
| 727 char** keys = argn(); | |
| 728 for (int ii = 0, len = argc(); ii < len; ++ii) { | |
| 729 if (!strcmp(keys[ii], key)) { | |
| 730 return argv()[ii]; | |
| 731 } | |
| 732 } | |
| 733 return NULL; | |
| 734 } | |
| 735 | |
| 736 void Plugin::AddPropertyGet(RpcFunction function_ptr, | |
| 737 const char* name, | |
| 738 const char* outs) { | |
| 739 uintptr_t method_id = browser_interface()->StringToIdentifier(name); | |
| 740 PLUGIN_PRINTF(("Plugin::AddPropertyGet (name='%s', id=%" | |
| 741 NACL_PRIxPTR")\n", name, method_id)); | |
| 742 MethodInfo* new_method = new MethodInfo(function_ptr, name, "", outs); | |
| 743 property_get_methods_.AddMethod(method_id, new_method); | |
| 744 } | |
| 745 | |
| 746 MethodInfo* Plugin::GetMethodInfo(uintptr_t method_id, CallType call_type) { | |
| 747 MethodInfo* method_info = NULL; | |
| 748 switch (call_type) { | |
| 749 case PROPERTY_GET: | |
| 750 method_info = property_get_methods_.GetMethod(method_id); | |
| 751 break; | |
| 752 case PROPERTY_SET: | |
| 753 case METHOD_CALL: | |
| 754 break; | |
| 755 } | |
| 756 PLUGIN_PRINTF(("Plugin::GetMethodInfo (id=%"NACL_PRIxPTR", " | |
| 757 "return %p)\n", method_id, static_cast<void*>(method_info))); | |
| 758 return method_info; | |
| 759 } | |
| 760 | |
| 761 class ProgressEvent { | |
| 762 public: | |
| 763 ProgressEvent(const char* event_type, | |
| 764 Plugin::LengthComputable length_computable, | |
| 765 uint64_t loaded_bytes, | |
| 766 uint64_t total_bytes) : | |
| 767 event_type_(event_type), | |
| 768 length_computable_(length_computable), | |
| 769 loaded_bytes_(loaded_bytes), | |
| 770 total_bytes_(total_bytes) { } | |
| 771 const char* event_type() const { return event_type_; } | |
| 772 Plugin::LengthComputable length_computable() const { | |
| 773 return length_computable_; | |
| 774 } | |
| 775 uint64_t loaded_bytes() const { return loaded_bytes_; } | |
| 776 uint64_t total_bytes() const { return total_bytes_; } | |
| 777 | |
| 778 private: | |
| 779 // event_type_ is always passed from a string literal, so ownership is | |
| 780 // not taken. Hence it does not need to be deleted when ProgressEvent is | |
| 781 // destroyed. | |
| 782 const char* event_type_; | |
| 783 Plugin::LengthComputable length_computable_; | |
| 784 uint64_t loaded_bytes_; | |
| 785 uint64_t total_bytes_; | |
| 786 }; | |
| 787 | |
| 788 const char* const Plugin::kNaClMIMEType = "application/x-nacl"; | |
| 789 | |
| 790 bool Plugin::IsForeignMIMEType() const { | |
| 791 return | |
| 792 !mime_type().empty() && | |
| 793 mime_type() != kNaClMIMEType; | |
| 794 } | |
| 795 | |
| 796 | |
| 797 Plugin* Plugin::New(PP_Instance pp_instance) { | |
| 798 PLUGIN_PRINTF(("Plugin::New (pp_instance=%"NACL_PRId32")\n", pp_instance)); | |
| 799 #if NACL_WINDOWS && !defined(NACL_STANDALONE) | |
| 800 if (!NaClHandlePassBrowserCtor()) { | |
| 801 return NULL; | |
| 802 } | |
| 803 #endif | |
| 804 Plugin* plugin = new(std::nothrow) Plugin(pp_instance); | |
| 805 PLUGIN_PRINTF(("Plugin::New (plugin=%p)\n", static_cast<void*>(plugin))); | |
| 806 if (plugin == NULL) { | |
| 807 return NULL; | |
| 808 } | |
| 809 return plugin; | |
| 810 } | |
| 811 | |
| 812 | |
| 813 // All failures of this function will show up as "Missing Plugin-in", so | |
| 814 // there is no need to log to JS console that there was an initialization | |
| 815 // failure. Note that module loading functions will log their own errors. | |
| 816 bool Plugin::Init(uint32_t argc, const char* argn[], const char* argv[]) { | |
| 817 PLUGIN_PRINTF(("Plugin::Init (argc=%"NACL_PRIu32")\n", argc)); | |
| 818 HistogramEnumerateOsArch(GetSandboxISA()); | |
| 819 init_time_ = NaClGetTimeOfDayMicroseconds(); | |
| 820 | |
| 821 BrowserInterface* browser_interface = new(std::nothrow) BrowserInterface; | |
| 822 if (browser_interface == NULL) { | |
| 823 return false; | |
| 824 } | |
| 825 ScriptableHandle* handle = ScriptableHandle::NewPlugin(this); | |
| 826 if (handle == NULL) { | |
| 827 return false; | |
| 828 } | |
| 829 set_scriptable_handle(handle); | |
| 830 PLUGIN_PRINTF(("Plugin::Init (scriptable_handle=%p)\n", | |
| 831 static_cast<void*>(scriptable_handle()))); | |
| 832 url_util_ = pp::URLUtil_Dev::Get(); | |
| 833 if (url_util_ == NULL) { | |
| 834 return false; | |
| 835 } | |
| 836 PLUGIN_PRINTF(("Plugin::Init (url_util_=%p)\n", | |
| 837 static_cast<const void*>(url_util_))); | |
| 838 | |
| 839 bool status = Plugin::Init( | |
| 840 browser_interface, | |
| 841 static_cast<int>(argc), | |
| 842 // TODO(polina): Can we change the args on our end to be const to | |
| 843 // avoid these ugly casts? | |
| 844 const_cast<char**>(argn), | |
| 845 const_cast<char**>(argv)); | |
| 846 if (status) { | |
| 847 const char* type_attr = LookupArgument(kTypeAttribute); | |
| 848 if (type_attr != NULL) { | |
| 849 mime_type_ = nacl::string(type_attr); | |
| 850 std::transform(mime_type_.begin(), mime_type_.end(), mime_type_.begin(), | |
| 851 tolower); | |
| 852 } | |
| 853 | |
| 854 const char* manifest_url = LookupArgument(kSrcManifestAttribute); | |
| 855 // If the MIME type is foreign, then 'src' will be the URL for the content | |
| 856 // and 'nacl' will be the URL for the manifest. | |
| 857 if (IsForeignMIMEType()) { | |
| 858 manifest_url = LookupArgument(kNaClManifestAttribute); | |
| 859 enable_dev_interface_ = RequiresDevInterface(manifest_url); | |
| 860 } | |
| 861 // Use the document URL as the base for resolving relative URLs to find the | |
| 862 // manifest. This takes into account the setting of <base> tags that | |
| 863 // precede the embed/object. | |
| 864 CHECK(url_util_ != NULL); | |
| 865 pp::Var base_var = url_util_->GetDocumentURL(*this); | |
| 866 if (!base_var.is_string()) { | |
| 867 PLUGIN_PRINTF(("Plugin::Init (unable to find document url)\n")); | |
| 868 return false; | |
| 869 } | |
| 870 set_plugin_base_url(base_var.AsString()); | |
| 871 if (manifest_url == NULL) { | |
| 872 // TODO(sehr,polina): this should be a hard error when scripting | |
| 873 // the src property is no longer allowed. | |
| 874 PLUGIN_PRINTF(("Plugin::Init:" | |
| 875 " WARNING: no 'src' property, so no manifest loaded.\n")); | |
| 876 if (NULL != LookupArgument(kNaClManifestAttribute)) { | |
| 877 PLUGIN_PRINTF(("Plugin::Init:" | |
| 878 " WARNING: 'nacl' property is incorrect. Use 'src'.\n")); | |
| 879 } | |
| 880 } else { | |
| 881 // Issue a GET for the manifest_url. The manifest file will be parsed to | |
| 882 // determine the nexe URL. | |
| 883 // Sets src property to full manifest URL. | |
| 884 RequestNaClManifest(manifest_url); | |
| 885 } | |
| 886 } | |
| 887 | |
| 888 // Export a property to allow us to get the last error description. | |
| 889 AddPropertyGet(GetLastError, "lastError", "s"); | |
| 890 | |
| 891 PLUGIN_PRINTF(("Plugin::Init (status=%d)\n", status)); | |
| 892 return status; | |
| 893 } | |
| 894 | |
| 895 | |
| 896 Plugin::Plugin(PP_Instance pp_instance) | |
| 897 : pp::InstancePrivate(pp_instance), | |
| 898 browser_interface_(NULL), | |
| 899 scriptable_handle_(NULL), | |
| 900 argc_(-1), | |
| 901 argn_(NULL), | |
| 902 argv_(NULL), | |
| 903 main_subprocess_(kMainSubprocessId, NULL, NULL), | |
| 904 nacl_ready_state_(UNSENT), | |
| 905 wrapper_factory_(NULL), | |
| 906 last_error_string_(""), | |
| 907 ppapi_proxy_(NULL), | |
| 908 enable_dev_interface_(false), | |
| 909 replayDidChangeView(false), | |
| 910 replayHandleDocumentLoad(false), | |
| 911 init_time_(0), | |
| 912 ready_time_(0), | |
| 913 nexe_size_(0) { | |
| 914 PLUGIN_PRINTF(("Plugin::Plugin (this=%p, pp_instance=%" | |
| 915 NACL_PRId32")\n", static_cast<void*>(this), pp_instance)); | |
| 916 NaClSrpcModuleInit(); | |
| 917 nexe_downloader_.Initialize(this); | |
| 918 pnacl_.Initialize(this); | |
| 919 callback_factory_.Initialize(this); | |
| 920 } | |
| 921 | |
| 922 | |
| 923 Plugin::~Plugin() { | |
| 924 int64_t shutdown_start = NaClGetTimeOfDayMicroseconds(); | |
| 925 | |
| 926 PLUGIN_PRINTF(("Plugin::~Plugin (this=%p, scriptable_handle=%p)\n", | |
| 927 static_cast<void*>(this), | |
| 928 static_cast<void*>(scriptable_handle()))); | |
| 929 | |
| 930 // If the proxy has been shutdown before now, it's likely the plugin suffered | |
| 931 // an error while loading. | |
| 932 if (ppapi_proxy_ != NULL) { | |
| 933 HistogramTimeLarge( | |
| 934 "NaCl.ModuleUptime.Normal", | |
| 935 (shutdown_start - ready_time_) / NACL_MICROS_PER_MILLI); | |
| 936 } | |
| 937 | |
| 938 #if NACL_WINDOWS && !defined(NACL_STANDALONE) | |
| 939 NaClHandlePassBrowserDtor(); | |
| 940 #endif | |
| 941 | |
| 942 url_downloaders_.erase(url_downloaders_.begin(), url_downloaders_.end()); | |
| 943 | |
| 944 ShutdownProxy(); | |
| 945 ScriptableHandle* scriptable_handle_ = scriptable_handle(); | |
| 946 ScriptableHandle::Unref(&scriptable_handle_); | |
| 947 NaClSrpcModuleFini(); | |
| 948 | |
| 949 // TODO(sehr,polina): We should not need to call ShutDownSubprocesses() here. | |
| 950 ShutDownSubprocesses(); | |
| 951 | |
| 952 delete wrapper_factory_; | |
| 953 delete browser_interface_; | |
| 954 delete[] argv_; | |
| 955 delete[] argn_; | |
| 956 | |
| 957 HistogramTimeSmall( | |
| 958 "NaCl.Perf.ShutdownTime.Total", | |
| 959 (NaClGetTimeOfDayMicroseconds() - shutdown_start) | |
| 960 / NACL_MICROS_PER_MILLI); | |
| 961 | |
| 962 PLUGIN_PRINTF(("Plugin::~Plugin (this=%p, return)\n", | |
| 963 static_cast<void*>(this))); | |
| 964 } | |
| 965 | |
| 966 | |
| 967 void Plugin::DidChangeView(const pp::Rect& position, const pp::Rect& clip) { | |
| 968 PLUGIN_PRINTF(("Plugin::DidChangeView (this=%p)\n", | |
| 969 static_cast<void*>(this))); | |
| 970 | |
| 971 if (!BrowserPpp::is_valid(ppapi_proxy_)) { | |
| 972 // Store this event and replay it when the proxy becomes available. | |
| 973 replayDidChangeView = true; | |
| 974 replayDidChangeViewPosition = position; | |
| 975 replayDidChangeViewClip = clip; | |
| 976 return; | |
| 977 } else { | |
| 978 ppapi_proxy_->ppp_instance_interface()->DidChangeView( | |
| 979 pp_instance(), &(position.pp_rect()), &(clip.pp_rect())); | |
| 980 } | |
| 981 } | |
| 982 | |
| 983 | |
| 984 void Plugin::DidChangeFocus(bool has_focus) { | |
| 985 PLUGIN_PRINTF(("Plugin::DidChangeFocus (this=%p)\n", | |
| 986 static_cast<void*>(this))); | |
| 987 if (!BrowserPpp::is_valid(ppapi_proxy_)) { | |
| 988 return; | |
| 989 } else { | |
| 990 ppapi_proxy_->ppp_instance_interface()->DidChangeFocus( | |
| 991 pp_instance(), PP_FromBool(has_focus)); | |
| 992 } | |
| 993 } | |
| 994 | |
| 995 | |
| 996 bool Plugin::HandleInputEvent(const pp::InputEvent& event) { | |
| 997 PLUGIN_PRINTF(("Plugin::HandleInputEvent (this=%p)\n", | |
| 998 static_cast<void*>(this))); | |
| 999 if (!BrowserPpp::is_valid(ppapi_proxy_) || | |
| 1000 ppapi_proxy_->ppp_input_event_interface() == NULL) { | |
| 1001 return false; // event is not handled here. | |
| 1002 } else { | |
| 1003 bool handled = PP_ToBool( | |
| 1004 ppapi_proxy_->ppp_input_event_interface()->HandleInputEvent( | |
| 1005 pp_instance(), event.pp_resource())); | |
| 1006 PLUGIN_PRINTF(("Plugin::HandleInputEvent (handled=%d)\n", handled)); | |
| 1007 return handled; | |
| 1008 } | |
| 1009 } | |
| 1010 | |
| 1011 | |
| 1012 bool Plugin::HandleDocumentLoad(const pp::URLLoader& url_loader) { | |
| 1013 PLUGIN_PRINTF(("Plugin::HandleDocumentLoad (this=%p)\n", | |
| 1014 static_cast<void*>(this))); | |
| 1015 if (!BrowserPpp::is_valid(ppapi_proxy_)) { | |
| 1016 // Store this event and replay it when the proxy becomes available. | |
| 1017 replayHandleDocumentLoad = true; | |
| 1018 replayHandleDocumentLoadURLLoader = url_loader; | |
| 1019 // Return true so that the browser keeps servicing this loader so we can | |
| 1020 // perform requests on it later. | |
| 1021 return true; | |
| 1022 } else { | |
| 1023 return PP_ToBool( | |
| 1024 ppapi_proxy_->ppp_instance_interface()->HandleDocumentLoad( | |
| 1025 pp_instance(), url_loader.pp_resource())); | |
| 1026 } | |
| 1027 } | |
| 1028 | |
| 1029 | |
| 1030 void Plugin::HandleMessage(const pp::Var& message) { | |
| 1031 PLUGIN_PRINTF(("Plugin::HandleMessage (this=%p)\n", | |
| 1032 static_cast<void*>(this))); | |
| 1033 if (BrowserPpp::is_valid(ppapi_proxy_) && | |
| 1034 ppapi_proxy_->ppp_messaging_interface() != NULL) { | |
| 1035 ppapi_proxy_->ppp_messaging_interface()->HandleMessage( | |
| 1036 pp_instance(), message.pp_var()); | |
| 1037 } | |
| 1038 } | |
| 1039 | |
| 1040 | |
| 1041 pp::Var Plugin::GetInstanceObject() { | |
| 1042 PLUGIN_PRINTF(("Plugin::GetInstanceObject (this=%p)\n", | |
| 1043 static_cast<void*>(this))); | |
| 1044 // The browser will unref when it discards the var for this object. | |
| 1045 ScriptableHandle* handle = | |
| 1046 static_cast<ScriptableHandle*>(scriptable_handle()->AddRef()); | |
| 1047 pp::Var* handle_var = handle->var(); | |
| 1048 PLUGIN_PRINTF(("Plugin::GetInstanceObject (handle=%p, handle_var=%p)\n", | |
| 1049 static_cast<void*>(handle), static_cast<void*>(handle_var))); | |
| 1050 return *handle_var; // make a copy | |
| 1051 } | |
| 1052 | |
| 1053 void Plugin::HistogramStartupTimeSmall(const std::string& name, float dt) { | |
| 1054 if (nexe_size_ > 0) { | |
| 1055 float size_in_MB = static_cast<float>(nexe_size_) / (1024.f * 1024.f); | |
| 1056 HistogramTimeSmall(name, static_cast<int64_t>(dt)); | |
| 1057 HistogramTimeSmall(name + "PerMB", static_cast<int64_t>(dt / size_in_MB)); | |
| 1058 } | |
| 1059 } | |
| 1060 | |
| 1061 void Plugin::HistogramStartupTimeMedium(const std::string& name, float dt) { | |
| 1062 if (nexe_size_ > 0) { | |
| 1063 float size_in_MB = static_cast<float>(nexe_size_) / (1024.f * 1024.f); | |
| 1064 HistogramTimeMedium(name, static_cast<int64_t>(dt)); | |
| 1065 HistogramTimeMedium(name + "PerMB", static_cast<int64_t>(dt / size_in_MB)); | |
| 1066 } | |
| 1067 } | |
| 1068 | |
| 1069 void Plugin::NexeFileDidOpen(int32_t pp_error) { | |
| 1070 PLUGIN_PRINTF(("Plugin::NexeFileDidOpen (pp_error=%"NACL_PRId32")\n", | |
| 1071 pp_error)); | |
| 1072 int32_t file_desc = nexe_downloader_.GetPOSIXFileDescriptor(); | |
| 1073 PLUGIN_PRINTF(("Plugin::NexeFileDidOpen (file_desc=%"NACL_PRId32")\n", | |
| 1074 file_desc)); | |
| 1075 ErrorInfo error_info; | |
| 1076 if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) { | |
| 1077 if (pp_error == PP_ERROR_ABORTED) { | |
| 1078 ReportLoadAbort(); | |
| 1079 } else { | |
| 1080 error_info.SetReport(ERROR_NEXE_LOAD_URL, "could not load nexe url."); | |
| 1081 ReportLoadError(error_info); | |
| 1082 } | |
| 1083 return; | |
| 1084 } | |
| 1085 int32_t file_desc_ok_to_close = DUP(file_desc); | |
| 1086 if (file_desc_ok_to_close == NACL_NO_FILE_DESC) { | |
| 1087 error_info.SetReport(ERROR_NEXE_FH_DUP, | |
| 1088 "could not duplicate loaded file handle."); | |
| 1089 ReportLoadError(error_info); | |
| 1090 return; | |
| 1091 } | |
| 1092 struct stat stat_buf; | |
| 1093 if (0 != fstat(file_desc_ok_to_close, &stat_buf)) { | |
| 1094 CLOSE(file_desc_ok_to_close); | |
| 1095 error_info.SetReport(ERROR_NEXE_STAT, "could not stat nexe file."); | |
| 1096 ReportLoadError(error_info); | |
| 1097 return; | |
| 1098 } | |
| 1099 size_t nexe_bytes_read = static_cast<size_t>(stat_buf.st_size); | |
| 1100 | |
| 1101 nexe_size_ = nexe_bytes_read; | |
| 1102 HistogramSizeKB("NaCl.Perf.Size.Nexe", | |
| 1103 static_cast<int32_t>(nexe_size_ / 1024)); | |
| 1104 HistogramStartupTimeMedium( | |
| 1105 "NaCl.Perf.StartupTime.NexeDownload", | |
| 1106 static_cast<float>(nexe_downloader_.TimeSinceOpenMilliseconds())); | |
| 1107 | |
| 1108 // Inform JavaScript that we successfully downloaded the nacl module. | |
| 1109 EnqueueProgressEvent("progress", | |
| 1110 LENGTH_IS_COMPUTABLE, | |
| 1111 nexe_bytes_read, | |
| 1112 nexe_bytes_read); | |
| 1113 | |
| 1114 load_start_ = NaClGetTimeOfDayMicroseconds(); | |
| 1115 nacl::scoped_ptr<nacl::DescWrapper> | |
| 1116 wrapper(wrapper_factory()->MakeFileDesc(file_desc_ok_to_close, O_RDONLY)); | |
| 1117 NaClLog(4, "NexeFileDidOpen: invoking LoadNaClModule\n"); | |
| 1118 bool was_successful = LoadNaClModule( | |
| 1119 wrapper.get(), &error_info, | |
| 1120 callback_factory_.NewCallback(&Plugin::NexeFileDidOpenContinuation)); | |
| 1121 | |
| 1122 if (!was_successful) { | |
| 1123 ReportLoadError(error_info); | |
| 1124 } | |
| 1125 } | |
| 1126 | |
| 1127 void Plugin::NexeFileDidOpenContinuation(int32_t pp_error) { | |
| 1128 ErrorInfo error_info; | |
| 1129 bool was_successful; | |
| 1130 | |
| 1131 UNREFERENCED_PARAMETER(pp_error); | |
| 1132 NaClLog(4, "Entered NexeFileDidOpenContinuation\n"); | |
| 1133 NaClLog(4, "NexeFileDidOpenContinuation: invoking" | |
| 1134 " LoadNaClModuleContinuationIntern\n"); | |
| 1135 was_successful = LoadNaClModuleContinuationIntern(&error_info); | |
| 1136 if (was_successful) { | |
| 1137 NaClLog(4, "NexeFileDidOpenContinuation: success;" | |
| 1138 " setting histograms\n"); | |
| 1139 ready_time_ = NaClGetTimeOfDayMicroseconds(); | |
| 1140 HistogramStartupTimeSmall( | |
| 1141 "NaCl.Perf.StartupTime.LoadModule", | |
| 1142 static_cast<float>(ready_time_ - load_start_) / NACL_MICROS_PER_MILLI); | |
| 1143 HistogramStartupTimeMedium( | |
| 1144 "NaCl.Perf.StartupTime.Total", | |
| 1145 static_cast<float>(ready_time_ - init_time_) / NACL_MICROS_PER_MILLI); | |
| 1146 | |
| 1147 ReportLoadSuccess(LENGTH_IS_COMPUTABLE, nexe_size_, nexe_size_); | |
| 1148 } else { | |
| 1149 NaClLog(4, "NexeFileDidOpenContinuation: failed."); | |
| 1150 ReportLoadError(error_info); | |
| 1151 } | |
| 1152 NaClLog(4, "Leaving NexeFileDidOpenContinuation\n"); | |
| 1153 } | |
| 1154 | |
| 1155 void Plugin::BitcodeDidTranslate(int32_t pp_error) { | |
| 1156 PLUGIN_PRINTF(("Plugin::BitcodeDidTranslate (pp_error=%"NACL_PRId32")\n", | |
| 1157 pp_error)); | |
| 1158 if (pp_error != PP_OK) { | |
| 1159 // Error should have been reported by pnacl. Just return. | |
| 1160 PLUGIN_PRINTF(("Plugin::BitcodeDidTranslate error in Pnacl\n")); | |
| 1161 return; | |
| 1162 } | |
| 1163 // Inform JavaScript that we successfully translated the bitcode to a nexe. | |
| 1164 EnqueueProgressEvent("progress", | |
| 1165 LENGTH_IS_NOT_COMPUTABLE, | |
| 1166 kUnknownBytes, | |
| 1167 kUnknownBytes); | |
| 1168 nacl::scoped_ptr<nacl::DescWrapper> | |
| 1169 wrapper(pnacl_.ReleaseTranslatedFD()); | |
| 1170 ErrorInfo error_info; | |
| 1171 bool was_successful = LoadNaClModule( | |
| 1172 wrapper.get(), &error_info, | |
| 1173 callback_factory_.NewCallback(&Plugin::BitcodeDidTranslateContinuation)); | |
| 1174 | |
| 1175 if (!was_successful) { | |
| 1176 ReportLoadError(error_info); | |
| 1177 } | |
| 1178 } | |
| 1179 | |
| 1180 void Plugin::BitcodeDidTranslateContinuation(int32_t pp_error) { | |
| 1181 ErrorInfo error_info; | |
| 1182 bool was_successful = LoadNaClModuleContinuationIntern(&error_info); | |
| 1183 | |
| 1184 NaClLog(4, "Entered BitcodeDidTranslateContinuation\n"); | |
| 1185 UNREFERENCED_PARAMETER(pp_error); | |
| 1186 if (was_successful) { | |
| 1187 ReportLoadSuccess(LENGTH_IS_NOT_COMPUTABLE, | |
| 1188 kUnknownBytes, | |
| 1189 kUnknownBytes); | |
| 1190 } else { | |
| 1191 ReportLoadError(error_info); | |
| 1192 } | |
| 1193 } | |
| 1194 | |
| 1195 // Check manifest_url and return whether or not to enable PPAPI Dev interfaces. | |
| 1196 // Returning true here will enable the PPAPI Dev interfaces regardless of | |
| 1197 // the environment variable NACL_ENABLE_PPAPI_DEV. | |
| 1198 bool Plugin::RequiresDevInterface(const nacl::string& manifest_url) { | |
| 1199 const char* extensions[] = { | |
| 1200 "chrome-extension://acadkphlmlegjaadjagenfimbpphcgnh/", // PDF | |
| 1201 }; | |
| 1202 for (size_t i = 0; i < sizeof(extensions) / sizeof(const char*); ++i) { | |
| 1203 if (manifest_url.find(extensions[i]) == 0) { | |
| 1204 return true; | |
| 1205 } | |
| 1206 } | |
| 1207 return false; | |
| 1208 } | |
| 1209 | |
| 1210 bool Plugin::StartProxiedExecution(NaClSrpcChannel* srpc_channel, | |
| 1211 ErrorInfo* error_info) { | |
| 1212 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (srpc_channel=%p)\n", | |
| 1213 static_cast<void*>(srpc_channel))); | |
| 1214 | |
| 1215 // Log the amound of time that has passed between the trusted plugin being | |
| 1216 // initialized and the untrusted plugin being initialized. This is (roughly) | |
| 1217 // the cost of using NaCl, in terms of startup time. | |
| 1218 HistogramStartupTimeMedium( | |
| 1219 "NaCl.Perf.StartupTime.NaClOverhead", | |
| 1220 static_cast<float>(NaClGetTimeOfDayMicroseconds() - init_time_) | |
| 1221 / NACL_MICROS_PER_MILLI); | |
| 1222 | |
| 1223 // Check that the .nexe exports the PPAPI intialization method. | |
| 1224 NaClSrpcService* client_service = srpc_channel->client; | |
| 1225 if (NaClSrpcServiceMethodIndex(client_service, | |
| 1226 "PPP_InitializeModule:iihs:ii") == | |
| 1227 kNaClSrpcInvalidMethodIndex) { | |
| 1228 error_info->SetReport( | |
| 1229 ERROR_START_PROXY_CHECK_PPP, | |
| 1230 "could not find PPP_InitializeModule() - toolchain version mismatch?"); | |
| 1231 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (%s)\n", | |
| 1232 error_info->message().c_str())); | |
| 1233 return false; | |
| 1234 } | |
| 1235 nacl::scoped_ptr<BrowserPpp> ppapi_proxy( | |
| 1236 new(std::nothrow) BrowserPpp(srpc_channel, this)); | |
| 1237 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (ppapi_proxy=%p)\n", | |
| 1238 static_cast<void*>(ppapi_proxy.get()))); | |
| 1239 if (ppapi_proxy.get() == NULL) { | |
| 1240 error_info->SetReport(ERROR_START_PROXY_ALLOC, | |
| 1241 "could not allocate proxy memory."); | |
| 1242 return false; | |
| 1243 } | |
| 1244 pp::Module* module = pp::Module::Get(); | |
| 1245 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (module=%p)\n", | |
| 1246 static_cast<void*>(module))); | |
| 1247 CHECK(module != NULL); // We could not have gotten past init stage otherwise. | |
| 1248 int32_t pp_error = | |
| 1249 ppapi_proxy->InitializeModule(module->pp_module(), | |
| 1250 module->get_browser_interface()); | |
| 1251 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (pp_error=%" | |
| 1252 NACL_PRId32")\n", pp_error)); | |
| 1253 if (pp_error != PP_OK) { | |
| 1254 error_info->SetReport(ERROR_START_PROXY_MODULE, | |
| 1255 "could not initialize module."); | |
| 1256 return false; | |
| 1257 } | |
| 1258 const PPP_Instance* instance_interface = | |
| 1259 ppapi_proxy->ppp_instance_interface(); | |
| 1260 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (ppp_instance=%p)\n", | |
| 1261 static_cast<const void*>(instance_interface))); | |
| 1262 CHECK(instance_interface != NULL); // Verified on module initialization. | |
| 1263 PP_Bool did_create = instance_interface->DidCreate( | |
| 1264 pp_instance(), | |
| 1265 argc(), | |
| 1266 const_cast<const char**>(argn()), | |
| 1267 const_cast<const char**>(argv())); | |
| 1268 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (did_create=%d)\n", | |
| 1269 did_create)); | |
| 1270 if (did_create == PP_FALSE) { | |
| 1271 error_info->SetReport(ERROR_START_PROXY_INSTANCE, | |
| 1272 "could not create instance."); | |
| 1273 return false; | |
| 1274 } | |
| 1275 | |
| 1276 ppapi_proxy_ = ppapi_proxy.release(); | |
| 1277 | |
| 1278 // Create PPP* interface adapters to forward calls to .nexe. | |
| 1279 find_adapter_.reset(new(std::nothrow) FindAdapter(this)); | |
| 1280 printing_adapter_.reset(new(std::nothrow) PrintingAdapter(this)); | |
| 1281 selection_adapter_.reset(new(std::nothrow) SelectionAdapter(this)); | |
| 1282 widget_client_adapter_.reset(new(std::nothrow) WidgetClientAdapter(this)); | |
| 1283 zoom_adapter_.reset(new(std::nothrow) ZoomAdapter(this)); | |
| 1284 | |
| 1285 // Replay missed events. | |
| 1286 if (replayDidChangeView) { | |
| 1287 replayDidChangeView = false; | |
| 1288 DidChangeView(replayDidChangeViewPosition, replayDidChangeViewClip); | |
| 1289 } | |
| 1290 if (replayHandleDocumentLoad) { | |
| 1291 replayHandleDocumentLoad = false; | |
| 1292 HandleDocumentLoad(replayHandleDocumentLoadURLLoader); | |
| 1293 // Release our reference on this loader. | |
| 1294 replayHandleDocumentLoadURLLoader = pp::URLLoader(); | |
| 1295 } | |
| 1296 bool is_valid_proxy = BrowserPpp::is_valid(ppapi_proxy_); | |
| 1297 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (is_valid_proxy=%d)\n", | |
| 1298 is_valid_proxy)); | |
| 1299 if (!is_valid_proxy) { | |
| 1300 error_info->SetReport(ERROR_START_PROXY_CRASH, | |
| 1301 "instance crashed after creation."); | |
| 1302 } | |
| 1303 return is_valid_proxy; | |
| 1304 } | |
| 1305 | |
| 1306 void Plugin::ReportDeadNexe() { | |
| 1307 PLUGIN_PRINTF(("Plugin::ReportDeadNexe\n")); | |
| 1308 | |
| 1309 if (nacl_ready_state() == DONE) { // After loadEnd. | |
| 1310 int64_t crash_time = NaClGetTimeOfDayMicroseconds(); | |
| 1311 // Crashes will be more likely near startup, so use a medium histogram | |
| 1312 // instead of a large one. | |
| 1313 HistogramTimeMedium( | |
| 1314 "NaCl.ModuleUptime.Crash", | |
| 1315 (crash_time - ready_time_) / NACL_MICROS_PER_MILLI); | |
| 1316 | |
| 1317 EnqueueProgressEvent("crash", | |
| 1318 LENGTH_IS_NOT_COMPUTABLE, | |
| 1319 kUnknownBytes, | |
| 1320 kUnknownBytes); | |
| 1321 CHECK(ppapi_proxy_ != NULL && !ppapi_proxy_->is_valid()); | |
| 1322 ShutdownProxy(); | |
| 1323 } | |
| 1324 // else LoadNaClModule and NexeFileDidOpen will provide error handling. | |
| 1325 // NOTE: not all crashes during load will make it here. | |
| 1326 // Those in BrowserPpp::InitializeModule and creation of PPP interfaces | |
| 1327 // will just get reported back as PP_ERROR_FAILED. | |
| 1328 } | |
| 1329 | |
| 1330 void Plugin::ShutdownProxy() { | |
| 1331 PLUGIN_PRINTF(("Plugin::ShutdownProxy (ppapi_proxy=%p)\n", | |
| 1332 static_cast<void*>(ppapi_proxy_))); | |
| 1333 // We do not call remote PPP_Instance::DidDestroy because the untrusted | |
| 1334 // side can no longer take full advantage of mostly asynchronous Pepper | |
| 1335 // per-Instance interfaces at this point. | |
| 1336 if (BrowserPpp::is_valid(ppapi_proxy_)) | |
| 1337 ppapi_proxy_->ShutdownModule(); | |
| 1338 delete ppapi_proxy_; | |
| 1339 ppapi_proxy_ = NULL; | |
| 1340 } | |
| 1341 | |
| 1342 void Plugin::NaClManifestBufferReady(int32_t pp_error) { | |
| 1343 PLUGIN_PRINTF(("Plugin::NaClManifestBufferReady (pp_error=%" | |
| 1344 NACL_PRId32")\n", pp_error)); | |
| 1345 ErrorInfo error_info; | |
| 1346 set_manifest_url(nexe_downloader_.url()); | |
| 1347 if (pp_error != PP_OK) { | |
| 1348 if (pp_error == PP_ERROR_ABORTED) { | |
| 1349 ReportLoadAbort(); | |
| 1350 } else { | |
| 1351 error_info.SetReport(ERROR_MANIFEST_LOAD_URL, | |
| 1352 "could not load manifest url."); | |
| 1353 ReportLoadError(error_info); | |
| 1354 } | |
| 1355 return; | |
| 1356 } | |
| 1357 | |
| 1358 const std::deque<char>& buffer = nexe_downloader_.buffer(); | |
| 1359 size_t buffer_size = buffer.size(); | |
| 1360 if (buffer_size > kNaClManifestMaxFileBytes) { | |
| 1361 error_info.SetReport(ERROR_MANIFEST_TOO_LARGE, | |
| 1362 "manifest file too large."); | |
| 1363 ReportLoadError(error_info); | |
| 1364 return; | |
| 1365 } | |
| 1366 nacl::scoped_array<char> json_buffer(new char[buffer_size + 1]); | |
| 1367 if (json_buffer == NULL) { | |
| 1368 error_info.SetReport(ERROR_MANIFEST_MEMORY_ALLOC, | |
| 1369 "could not allocate manifest memory."); | |
| 1370 ReportLoadError(error_info); | |
| 1371 return; | |
| 1372 } | |
| 1373 std::copy(buffer.begin(), buffer.begin() + buffer_size, &json_buffer[0]); | |
| 1374 json_buffer[buffer_size] = '\0'; | |
| 1375 | |
| 1376 ProcessNaClManifest(json_buffer.get()); | |
| 1377 } | |
| 1378 | |
| 1379 void Plugin::NaClManifestFileDidOpen(int32_t pp_error) { | |
| 1380 PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen (pp_error=%" | |
| 1381 NACL_PRId32")\n", pp_error)); | |
| 1382 HistogramTimeSmall("NaCl.Perf.StartupTime.ManifestDownload", | |
| 1383 nexe_downloader_.TimeSinceOpenMilliseconds()); | |
| 1384 ErrorInfo error_info; | |
| 1385 // The manifest file was successfully opened. Set the src property on the | |
| 1386 // plugin now, so that the full url is available to error handlers. | |
| 1387 set_manifest_url(nexe_downloader_.url()); | |
| 1388 int32_t file_desc = nexe_downloader_.GetPOSIXFileDescriptor(); | |
| 1389 PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen (file_desc=%" | |
| 1390 NACL_PRId32")\n", file_desc)); | |
| 1391 if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) { | |
| 1392 if (pp_error == PP_ERROR_ABORTED) { | |
| 1393 ReportLoadAbort(); | |
| 1394 } else { | |
| 1395 error_info.SetReport(ERROR_MANIFEST_LOAD_URL, | |
| 1396 "could not load manifest url."); | |
| 1397 ReportLoadError(error_info); | |
| 1398 } | |
| 1399 return; | |
| 1400 } | |
| 1401 // Duplicate the file descriptor in order to create a FILE stream with it | |
| 1402 // that can later be closed without closing the original descriptor. The | |
| 1403 // browser will take care of the original descriptor. | |
| 1404 int dup_file_desc = DUP(file_desc); | |
| 1405 struct stat stat_buf; | |
| 1406 if (0 != fstat(dup_file_desc, &stat_buf)) { | |
| 1407 CLOSE(dup_file_desc); | |
| 1408 error_info.SetReport(ERROR_MANIFEST_STAT, | |
| 1409 "could not stat manifest file."); | |
| 1410 ReportLoadError(error_info); | |
| 1411 return; | |
| 1412 } | |
| 1413 size_t bytes_to_read = static_cast<size_t>(stat_buf.st_size); | |
| 1414 if (bytes_to_read > kNaClManifestMaxFileBytes) { | |
| 1415 CLOSE(dup_file_desc); | |
| 1416 error_info.SetReport(ERROR_MANIFEST_TOO_LARGE, | |
| 1417 "manifest file too large."); | |
| 1418 ReportLoadError(error_info); | |
| 1419 return; | |
| 1420 } | |
| 1421 FILE* json_file = fdopen(dup_file_desc, "rb"); | |
| 1422 PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen " | |
| 1423 "(dup_file_desc=%"NACL_PRId32", json_file=%p)\n", | |
| 1424 dup_file_desc, static_cast<void*>(json_file))); | |
| 1425 if (json_file == NULL) { | |
| 1426 CLOSE(dup_file_desc); | |
| 1427 error_info.SetReport(ERROR_MANIFEST_OPEN, | |
| 1428 "could not open manifest file."); | |
| 1429 ReportLoadError(error_info); | |
| 1430 return; | |
| 1431 } | |
| 1432 nacl::scoped_array<char> json_buffer(new char[bytes_to_read + 1]); | |
| 1433 if (json_buffer == NULL) { | |
| 1434 fclose(json_file); | |
| 1435 error_info.SetReport(ERROR_MANIFEST_MEMORY_ALLOC, | |
| 1436 "could not allocate manifest memory."); | |
| 1437 ReportLoadError(error_info); | |
| 1438 return; | |
| 1439 } | |
| 1440 // json_buffer could hold a large enough buffer that the system might need | |
| 1441 // multiple reads to fill it, so iterate through reads. | |
| 1442 size_t total_bytes_read = 0; | |
| 1443 while (0 < bytes_to_read) { | |
| 1444 size_t bytes_this_read = fread(&json_buffer[total_bytes_read], | |
| 1445 sizeof(char), | |
| 1446 bytes_to_read, | |
| 1447 json_file); | |
| 1448 if (bytes_this_read < bytes_to_read && | |
| 1449 (feof(json_file) || ferror(json_file))) { | |
| 1450 PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen failed: " | |
| 1451 "total_bytes_read=%"NACL_PRIuS" " | |
| 1452 "bytes_to_read=%"NACL_PRIuS"\n", | |
| 1453 total_bytes_read, bytes_to_read)); | |
| 1454 fclose(json_file); | |
| 1455 error_info.SetReport(ERROR_MANIFEST_READ, | |
| 1456 "could not read manifest file."); | |
| 1457 ReportLoadError(error_info); | |
| 1458 return; | |
| 1459 } | |
| 1460 total_bytes_read += bytes_this_read; | |
| 1461 bytes_to_read -= bytes_this_read; | |
| 1462 } | |
| 1463 // Once the bytes are read, the FILE is no longer needed, so close it. This | |
| 1464 // allows for early returns without leaking the |json_file| FILE object. | |
| 1465 fclose(json_file); | |
| 1466 // No need to close |file_desc|, that is handled by |nexe_downloader_|. | |
| 1467 json_buffer[total_bytes_read] = '\0'; // Force null termination. | |
| 1468 | |
| 1469 ProcessNaClManifest(json_buffer.get()); | |
| 1470 } | |
| 1471 | |
| 1472 void Plugin::ProcessNaClManifest(const nacl::string& manifest_json) { | |
| 1473 HistogramSizeKB("NaCl.Perf.Size.Manifest", | |
| 1474 static_cast<int32_t>(manifest_json.length() / 1024)); | |
| 1475 nacl::string program_url; | |
| 1476 bool is_portable; | |
| 1477 ErrorInfo error_info; | |
| 1478 if (!SetManifestObject(manifest_json, &error_info)) { | |
| 1479 ReportLoadError(error_info); | |
| 1480 return; | |
| 1481 } | |
| 1482 | |
| 1483 if (SelectProgramURLFromManifest(&program_url, &error_info, &is_portable)) { | |
| 1484 set_nacl_ready_state(LOADING); | |
| 1485 // Inform JavaScript that we found a nexe URL to load. | |
| 1486 EnqueueProgressEvent("progress", | |
| 1487 LENGTH_IS_NOT_COMPUTABLE, | |
| 1488 kUnknownBytes, | |
| 1489 kUnknownBytes); | |
| 1490 if (is_portable) { | |
| 1491 // TODO(jvoung): Do we want to check an ENV var if pnacl is enabled first? | |
| 1492 nacl::string llc_url; | |
| 1493 nacl::string ld_url; | |
| 1494 if (SelectLLCURLFromManifest(&llc_url, &error_info) && | |
| 1495 SelectLDURLFromManifest(&ld_url, &error_info)) { | |
| 1496 pp::CompletionCallback translate_callback = | |
| 1497 callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate); | |
| 1498 // Will always call the callback on success or failure. | |
| 1499 pnacl_.BitcodeToNative(program_url, | |
| 1500 llc_url, | |
| 1501 ld_url, | |
| 1502 translate_callback); | |
| 1503 return; | |
| 1504 } | |
| 1505 } else { | |
| 1506 pp::CompletionCallback open_callback = | |
| 1507 callback_factory_.NewRequiredCallback(&Plugin::NexeFileDidOpen); | |
| 1508 // Will always call the callback on success or failure. | |
| 1509 CHECK( | |
| 1510 nexe_downloader_.Open(program_url, DOWNLOAD_TO_FILE, open_callback)); | |
| 1511 return; | |
| 1512 } | |
| 1513 } | |
| 1514 // Failed to select the program and/or the translator. | |
| 1515 ReportLoadError(error_info); | |
| 1516 } | |
| 1517 | |
| 1518 void Plugin::RequestNaClManifest(const nacl::string& url) { | |
| 1519 PLUGIN_PRINTF(("Plugin::RequestNaClManifest (url='%s')\n", url.c_str())); | |
| 1520 PLUGIN_PRINTF(("Plugin::RequestNaClManifest (plugin base url='%s')\n", | |
| 1521 plugin_base_url().c_str())); | |
| 1522 // The full URL of the manifest file is relative to the base url. | |
| 1523 CHECK(url_util_ != NULL); | |
| 1524 pp::Var nmf_resolved_url = | |
| 1525 url_util_->ResolveRelativeToURL(plugin_base_url(), pp::Var(url)); | |
| 1526 if (!nmf_resolved_url.is_string()) { | |
| 1527 ErrorInfo error_info; | |
| 1528 error_info.SetReport( | |
| 1529 ERROR_MANIFEST_RESOLVE_URL, | |
| 1530 nacl::string("could not resolve URL \"") + url.c_str() + | |
| 1531 "\" relative to \"" + plugin_base_url().c_str() + "\"."); | |
| 1532 ReportLoadError(error_info); | |
| 1533 return; | |
| 1534 } | |
| 1535 PLUGIN_PRINTF(("Plugin::RequestNaClManifest (resolved url='%s')\n", | |
| 1536 nmf_resolved_url.AsString().c_str())); | |
| 1537 set_manifest_base_url(nmf_resolved_url.AsString()); | |
| 1538 set_manifest_url(url); | |
| 1539 // Inform JavaScript that a load is starting. | |
| 1540 set_nacl_ready_state(OPENED); | |
| 1541 EnqueueProgressEvent("loadstart", | |
| 1542 LENGTH_IS_NOT_COMPUTABLE, | |
| 1543 kUnknownBytes, | |
| 1544 kUnknownBytes); | |
| 1545 bool is_data_uri = GetUrlScheme(nmf_resolved_url.AsString()) == SCHEME_DATA; | |
| 1546 HistogramEnumerateManifestIsDataURI(static_cast<int>(is_data_uri)); | |
| 1547 if (is_data_uri) { | |
| 1548 pp::CompletionCallback open_callback = | |
| 1549 callback_factory_.NewRequiredCallback(&Plugin::NaClManifestBufferReady); | |
| 1550 // Will always call the callback on success or failure. | |
| 1551 CHECK(nexe_downloader_.Open(nmf_resolved_url.AsString(), | |
| 1552 DOWNLOAD_TO_BUFFER, | |
| 1553 open_callback)); | |
| 1554 } else { | |
| 1555 pp::CompletionCallback open_callback = | |
| 1556 callback_factory_.NewRequiredCallback(&Plugin::NaClManifestFileDidOpen); | |
| 1557 // Will always call the callback on success or failure. | |
| 1558 CHECK(nexe_downloader_.Open(nmf_resolved_url.AsString(), | |
| 1559 DOWNLOAD_TO_FILE, | |
| 1560 open_callback)); | |
| 1561 } | |
| 1562 } | |
| 1563 | |
| 1564 | |
| 1565 bool Plugin::SetManifestObject(const nacl::string& manifest_json, | |
| 1566 ErrorInfo* error_info) { | |
| 1567 PLUGIN_PRINTF(("Plugin::SetManifestObject(): manifest_json='%s'.\n", | |
| 1568 manifest_json.c_str())); | |
| 1569 if (error_info == NULL) | |
| 1570 return false; | |
| 1571 manifest_.reset( | |
| 1572 new Manifest(url_util_, manifest_base_url(), GetSandboxISA())); | |
| 1573 if (!manifest_->Init(manifest_json, error_info)) { | |
| 1574 return false; | |
| 1575 } | |
| 1576 return true; | |
| 1577 } | |
| 1578 | |
| 1579 bool Plugin::SelectProgramURLFromManifest(nacl::string* result, | |
| 1580 ErrorInfo* error_info, | |
| 1581 bool* is_portable) { | |
| 1582 const nacl::string sandbox_isa(GetSandboxISA()); | |
| 1583 PLUGIN_PRINTF(("Plugin::SelectProgramURLFromManifest(): sandbox='%s'.\n", | |
| 1584 sandbox_isa.c_str())); | |
| 1585 if (result == NULL || error_info == NULL || manifest_ == NULL) | |
| 1586 return false; | |
| 1587 return manifest_->GetProgramURL(result, error_info, is_portable); | |
| 1588 } | |
| 1589 | |
| 1590 // TODO(jvoung): get rid of these when we have a better hosting solution | |
| 1591 // for PNaCl's nexes. | |
| 1592 bool Plugin::SelectLLCURLFromManifest(nacl::string* result, | |
| 1593 ErrorInfo* error_info) { | |
| 1594 PLUGIN_PRINTF(("Plugin::SelectLLCURLFromManifest()\n")); | |
| 1595 if (result == NULL || error_info == NULL || manifest_ == NULL) | |
| 1596 return false; | |
| 1597 return manifest_->GetLLCURL(result, error_info); | |
| 1598 } | |
| 1599 | |
| 1600 bool Plugin::SelectLDURLFromManifest(nacl::string* result, | |
| 1601 ErrorInfo* error_info) { | |
| 1602 PLUGIN_PRINTF(("Plugin::SelectLDURLFromManifest()\n")); | |
| 1603 if (result == NULL || error_info == NULL || manifest_ == NULL) | |
| 1604 return false; | |
| 1605 return manifest_->GetLDURL(result, error_info); | |
| 1606 } | |
| 1607 // end TODO(jvoung) | |
| 1608 | |
| 1609 | |
| 1610 void Plugin::UrlDidOpenForStreamAsFile(int32_t pp_error, | |
| 1611 FileDownloader*& url_downloader, | |
| 1612 PP_CompletionCallback callback) { | |
| 1613 PLUGIN_PRINTF(("Plugin::UrlDidOpen (pp_error=%"NACL_PRId32 | |
| 1614 ", url_downloader=%p)\n", pp_error, | |
| 1615 static_cast<void*>(url_downloader))); | |
| 1616 url_downloaders_.erase(url_downloader); | |
| 1617 nacl::scoped_ptr<FileDownloader> scoped_url_downloader(url_downloader); | |
| 1618 int32_t file_desc = scoped_url_downloader->GetPOSIXFileDescriptor(); | |
| 1619 | |
| 1620 if (pp_error != PP_OK) { | |
| 1621 PP_RunCompletionCallback(&callback, pp_error); | |
| 1622 } else if (file_desc > NACL_NO_FILE_DESC) { | |
| 1623 url_fd_map_[url_downloader->url_to_open()] = file_desc; | |
| 1624 PP_RunCompletionCallback(&callback, PP_OK); | |
| 1625 } else { | |
| 1626 PP_RunCompletionCallback(&callback, PP_ERROR_FAILED); | |
| 1627 } | |
| 1628 } | |
| 1629 | |
| 1630 int32_t Plugin::GetPOSIXFileDesc(const nacl::string& url) { | |
| 1631 PLUGIN_PRINTF(("Plugin::GetFileDesc (url=%s)\n", url.c_str())); | |
| 1632 int32_t file_desc_ok_to_close = NACL_NO_FILE_DESC; | |
| 1633 std::map<nacl::string, int32_t>::iterator it = url_fd_map_.find(url); | |
| 1634 if (it != url_fd_map_.end()) | |
| 1635 file_desc_ok_to_close = DUP(it->second); | |
| 1636 return file_desc_ok_to_close; | |
| 1637 } | |
| 1638 | |
| 1639 | |
| 1640 bool Plugin::StreamAsFile(const nacl::string& url, | |
| 1641 PP_CompletionCallback callback) { | |
| 1642 PLUGIN_PRINTF(("Plugin::StreamAsFile (url='%s')\n", url.c_str())); | |
| 1643 FileDownloader* downloader = new FileDownloader(); | |
| 1644 downloader->Initialize(this); | |
| 1645 url_downloaders_.insert(downloader); | |
| 1646 pp::CompletionCallback open_callback = | |
| 1647 callback_factory_.NewRequiredCallback( | |
| 1648 &Plugin::UrlDidOpenForStreamAsFile, downloader, callback); | |
| 1649 // Untrusted loads are always relative to the page's origin. | |
| 1650 CHECK(url_util_ != NULL); | |
| 1651 pp::Var resolved_url = | |
| 1652 url_util_->ResolveRelativeToURL(pp::Var(plugin_base_url()), url); | |
| 1653 if (!resolved_url.is_string()) { | |
| 1654 PLUGIN_PRINTF(("Plugin::StreamAsFile: " | |
| 1655 "could not resolve url \"%s\" relative to plugin \"%s\".", | |
| 1656 url.c_str(), | |
| 1657 plugin_base_url().c_str())); | |
| 1658 return false; | |
| 1659 } | |
| 1660 // If true, will always call the callback on success or failure. | |
| 1661 return downloader->Open(url, DOWNLOAD_TO_FILE, open_callback); | |
| 1662 } | |
| 1663 | |
| 1664 #ifndef HACK_FOR_MACOS_HANG_REMOVED | |
| 1665 // The following is needed to avoid a plugin startup hang in the | |
| 1666 // MacOS "chrome_browser_tests under gyp" stage. | |
| 1667 // TODO(sehr,mseaborn): remove this hack. | |
| 1668 void (plugin::Plugin::*pmem)(int32_t, | |
| 1669 plugin::FileDownloader*&, | |
| 1670 pp::VarPrivate&); | |
| 1671 void Plugin::XYZZY(const nacl::string& url, | |
| 1672 pp::VarPrivate js_callback) { | |
| 1673 UNREFERENCED_PARAMETER(url); | |
| 1674 UNREFERENCED_PARAMETER(js_callback); | |
| 1675 pp::CompletionCallback open_callback = | |
| 1676 callback_factory_.NewRequiredCallback(pmem, | |
| 1677 reinterpret_cast<plugin::FileDownloader*>(NULL), | |
| 1678 js_callback); | |
| 1679 } | |
| 1680 #endif // HACK_FOR_MACOS_HANG_REMOVED | |
| 1681 | |
| 1682 | |
| 1683 void Plugin::ReportLoadSuccess(LengthComputable length_computable, | |
| 1684 uint64_t loaded_bytes, | |
| 1685 uint64_t total_bytes) { | |
| 1686 // Set the readyState attribute to indicate loaded. | |
| 1687 set_nacl_ready_state(DONE); | |
| 1688 // Inform JavaScript that loading was successful and is complete. | |
| 1689 EnqueueProgressEvent("load", length_computable, loaded_bytes, total_bytes); | |
| 1690 EnqueueProgressEvent("loadend", length_computable, loaded_bytes, total_bytes); | |
| 1691 | |
| 1692 // UMA | |
| 1693 HistogramEnumerateLoadStatus(ERROR_LOAD_SUCCESS); | |
| 1694 } | |
| 1695 | |
| 1696 | |
| 1697 // TODO(ncbray): report UMA stats | |
| 1698 void Plugin::ReportLoadError(const ErrorInfo& error_info) { | |
| 1699 PLUGIN_PRINTF(("Plugin::ReportLoadError (error='%s')\n", | |
| 1700 error_info.message().c_str())); | |
| 1701 // Set the readyState attribute to indicate we need to start over. | |
| 1702 set_nacl_ready_state(DONE); | |
| 1703 // Report an error in lastError and on the JavaScript console. | |
| 1704 nacl::string message = nacl::string("NaCl module load failed: ") + | |
| 1705 error_info.message(); | |
| 1706 set_last_error_string(message); | |
| 1707 browser_interface()->AddToConsole(this, message); | |
| 1708 ShutdownProxy(); | |
| 1709 // Inform JavaScript that loading encountered an error and is complete. | |
| 1710 EnqueueProgressEvent("error", | |
| 1711 LENGTH_IS_NOT_COMPUTABLE, | |
| 1712 kUnknownBytes, | |
| 1713 kUnknownBytes); | |
| 1714 EnqueueProgressEvent("loadend", | |
| 1715 LENGTH_IS_NOT_COMPUTABLE, | |
| 1716 kUnknownBytes, | |
| 1717 kUnknownBytes); | |
| 1718 | |
| 1719 // UMA | |
| 1720 HistogramEnumerateLoadStatus(error_info.error_code()); | |
| 1721 } | |
| 1722 | |
| 1723 | |
| 1724 void Plugin::ReportLoadAbort() { | |
| 1725 PLUGIN_PRINTF(("Plugin::ReportLoadAbort\n")); | |
| 1726 // Set the readyState attribute to indicate we need to start over. | |
| 1727 set_nacl_ready_state(DONE); | |
| 1728 // Report an error in lastError and on the JavaScript console. | |
| 1729 nacl::string error_string("NaCl module load failed: user aborted"); | |
| 1730 set_last_error_string(error_string); | |
| 1731 browser_interface()->AddToConsole(this, error_string); | |
| 1732 ShutdownProxy(); | |
| 1733 // Inform JavaScript that loading was aborted and is complete. | |
| 1734 EnqueueProgressEvent("abort", | |
| 1735 LENGTH_IS_NOT_COMPUTABLE, | |
| 1736 kUnknownBytes, | |
| 1737 kUnknownBytes); | |
| 1738 EnqueueProgressEvent("loadend", | |
| 1739 LENGTH_IS_NOT_COMPUTABLE, | |
| 1740 kUnknownBytes, | |
| 1741 kUnknownBytes); | |
| 1742 | |
| 1743 // UMA | |
| 1744 HistogramEnumerateLoadStatus(ERROR_LOAD_ABORTED); | |
| 1745 } | |
| 1746 | |
| 1747 | |
| 1748 void Plugin::EnqueueProgressEvent(const char* event_type, | |
| 1749 LengthComputable length_computable, | |
| 1750 uint64_t loaded_bytes, | |
| 1751 uint64_t total_bytes) { | |
| 1752 PLUGIN_PRINTF(("Plugin::EnqueueProgressEvent (" | |
| 1753 "event_type='%s', length_computable=%d, " | |
| 1754 "loaded=%"NACL_PRIu64", total=%"NACL_PRIu64")\n", | |
| 1755 event_type, | |
| 1756 static_cast<int>(length_computable), | |
| 1757 loaded_bytes, | |
| 1758 total_bytes)); | |
| 1759 | |
| 1760 progress_events_.push(new ProgressEvent(event_type, | |
| 1761 length_computable, | |
| 1762 loaded_bytes, | |
| 1763 total_bytes)); | |
| 1764 // Note that using callback_factory_ in this way is not thread safe. | |
| 1765 // If/when EnqueueProgressEvent is callable from another thread, this | |
| 1766 // will need to change. | |
| 1767 pp::CompletionCallback callback = | |
| 1768 callback_factory_.NewCallback(&Plugin::DispatchProgressEvent); | |
| 1769 pp::Core* core = pp::Module::Get()->core(); | |
| 1770 core->CallOnMainThread(0, callback, 0); | |
| 1771 } | |
| 1772 | |
| 1773 void Plugin::ReportSelLdrLoadStatus(int status) { | |
| 1774 HistogramEnumerateSelLdrLoadStatus(static_cast<NaClErrorCode>(status)); | |
| 1775 } | |
| 1776 | |
| 1777 void Plugin::DispatchProgressEvent(int32_t result) { | |
| 1778 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent (result=%" | |
| 1779 NACL_PRId32")\n", result)); | |
| 1780 if (result < 0) { | |
| 1781 return; | |
| 1782 } | |
| 1783 if (progress_events_.empty()) { | |
| 1784 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent: no pending events\n")); | |
| 1785 return; | |
| 1786 } | |
| 1787 nacl::scoped_ptr<ProgressEvent> event(progress_events_.front()); | |
| 1788 progress_events_.pop(); | |
| 1789 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent (" | |
| 1790 "event_type='%s', length_computable=%d, " | |
| 1791 "loaded=%"NACL_PRIu64", total=%"NACL_PRIu64")\n", | |
| 1792 event->event_type(), | |
| 1793 static_cast<int>(event->length_computable()), | |
| 1794 event->loaded_bytes(), | |
| 1795 event->total_bytes())); | |
| 1796 | |
| 1797 static const char* kEventClosureJS = | |
| 1798 "(function(target, type, lengthComputable, loadedBytes, totalBytes) {" | |
| 1799 " var progress_event = document.createEvent('ProgressEvent');" | |
| 1800 " progress_event.initProgressEvent(type, false, true," | |
| 1801 " lengthComputable," | |
| 1802 " loadedBytes," | |
| 1803 " totalBytes);" | |
| 1804 " target.dispatchEvent(progress_event);" | |
| 1805 "})"; | |
| 1806 | |
| 1807 // Create a function object by evaluating the JavaScript text. | |
| 1808 // TODO(sehr, polina): We should probably cache the created function object to | |
| 1809 // avoid JavaScript reparsing. | |
| 1810 pp::VarPrivate exception; | |
| 1811 pp::VarPrivate function_object = ExecuteScript(kEventClosureJS, &exception); | |
| 1812 if (!exception.is_undefined() || !function_object.is_object()) { | |
| 1813 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent:" | |
| 1814 " Function object creation failed.\n")); | |
| 1815 return; | |
| 1816 } | |
| 1817 // Get the target of the event to be dispatched. | |
| 1818 pp::Var owner_element_object = GetOwnerElementObject(); | |
| 1819 if (!owner_element_object.is_object()) { | |
| 1820 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent:" | |
| 1821 " Couldn't get owner element object.\n")); | |
| 1822 NACL_NOTREACHED(); | |
| 1823 return; | |
| 1824 } | |
| 1825 | |
| 1826 pp::Var argv[5]; | |
| 1827 static const uint32_t argc = NACL_ARRAY_SIZE(argv); | |
| 1828 argv[0] = owner_element_object; | |
| 1829 argv[1] = pp::Var(event->event_type()); | |
| 1830 argv[2] = pp::Var(event->length_computable() == LENGTH_IS_COMPUTABLE); | |
| 1831 argv[3] = pp::Var(static_cast<double>(event->loaded_bytes())); | |
| 1832 argv[4] = pp::Var(static_cast<double>(event->total_bytes())); | |
| 1833 | |
| 1834 // Dispatch the event. | |
| 1835 const pp::Var default_method; | |
| 1836 function_object.Call(default_method, argc, argv, &exception); | |
| 1837 if (!exception.is_undefined()) { | |
| 1838 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent:" | |
| 1839 " event dispatch failed.\n")); | |
| 1840 } | |
| 1841 } | |
| 1842 | |
| 1843 UrlSchemeType Plugin::GetUrlScheme(const std::string& url) { | |
| 1844 CHECK(url_util_ != NULL); | |
| 1845 PP_URLComponents_Dev comps; | |
| 1846 pp::Var canonicalized = | |
| 1847 url_util_->Canonicalize(pp::Var(url), &comps); | |
| 1848 | |
| 1849 if (canonicalized.is_null() || | |
| 1850 (comps.scheme.begin == 0 && comps.scheme.len == -1)) { | |
| 1851 // |url| was an invalid URL or has no scheme. | |
| 1852 return SCHEME_OTHER; | |
| 1853 } | |
| 1854 | |
| 1855 CHECK(comps.scheme.begin < | |
| 1856 static_cast<int>(canonicalized.AsString().size())); | |
| 1857 CHECK(comps.scheme.begin + comps.scheme.len < | |
| 1858 static_cast<int>(canonicalized.AsString().size())); | |
| 1859 | |
| 1860 std::string scheme = canonicalized.AsString().substr(comps.scheme.begin, | |
| 1861 comps.scheme.len); | |
| 1862 if (scheme == kChromeExtensionUriScheme) | |
| 1863 return SCHEME_CHROME_EXTENSION; | |
| 1864 if (scheme == kDataUriScheme) | |
| 1865 return SCHEME_DATA; | |
| 1866 return SCHEME_OTHER; | |
| 1867 } | |
| 1868 | |
| 1869 } // namespace plugin | |
| OLD | NEW |