| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2008 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 "chrome/plugin/chrome_plugin_host.h" | |
| 6 | |
| 7 #include "base/file_util.h" | |
| 8 #include "base/message_loop.h" | |
| 9 #include "chrome/common/chrome_constants.h" | |
| 10 #include "chrome/common/chrome_plugin_lib.h" | |
| 11 #include "chrome/common/chrome_plugin_util.h" | |
| 12 #include "chrome/common/render_messages.h" | |
| 13 #include "chrome/common/resource_dispatcher.h" | |
| 14 #include "chrome/renderer/render_thread.h" | |
| 15 #include "chrome/renderer/render_view.h" | |
| 16 #include "net/base/data_url.h" | |
| 17 #include "net/base/upload_data.h" | |
| 18 #include "webkit/glue/plugins/plugin_instance.h" | |
| 19 #include "webkit/glue/resource_loader_bridge.h" | |
| 20 #include "webkit/glue/resource_type.h" | |
| 21 #include "webkit/glue/webkit_glue.h" | |
| 22 #include "webkit/glue/webframe.h" | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 using webkit_glue::ResourceLoaderBridge; | |
| 27 | |
| 28 // This class manages a network request made by the plugin, handling the | |
| 29 // data as it comes in from the ResourceLoaderBridge and is requested by the | |
| 30 // plugin. | |
| 31 // NOTE: All methods must be called on the Plugin thread. | |
| 32 class PluginRequestHandlerProxy | |
| 33 : public PluginHelper, public ResourceLoaderBridge::Peer { | |
| 34 public: | |
| 35 static PluginRequestHandlerProxy* FromCPRequest(CPRequest* request) { | |
| 36 return ScopableCPRequest::GetData<PluginRequestHandlerProxy*>(request); | |
| 37 } | |
| 38 | |
| 39 PluginRequestHandlerProxy(ChromePluginLib* plugin, | |
| 40 ScopableCPRequest* cprequest, | |
| 41 WebFrame* webframe) | |
| 42 : PluginHelper(plugin), cprequest_(cprequest), response_data_offset_(0), | |
| 43 completed_(false), sync_(false), read_buffer_(NULL), | |
| 44 webframe_(webframe) { | |
| 45 load_flags_ = PluginResponseUtils::CPLoadFlagsToNetFlags(0); | |
| 46 cprequest_->data = this; // see FromCPRequest(). | |
| 47 } | |
| 48 | |
| 49 ~PluginRequestHandlerProxy() { | |
| 50 if (bridge_.get() && !completed_) { | |
| 51 bridge_->Cancel(); | |
| 52 } | |
| 53 } | |
| 54 | |
| 55 // ResourceLoaderBridge::Peer | |
| 56 virtual void OnUploadProgress(uint64 position, uint64 size) { | |
| 57 CPRR_UploadProgressFunc upload_progress = | |
| 58 plugin_->functions().response_funcs->upload_progress; | |
| 59 if (upload_progress) | |
| 60 upload_progress(cprequest_.get(), position, size); | |
| 61 } | |
| 62 | |
| 63 virtual void OnReceivedRedirect(const GURL& new_url) { | |
| 64 plugin_->functions().response_funcs->received_redirect( | |
| 65 cprequest_.get(), new_url.spec().c_str()); | |
| 66 } | |
| 67 | |
| 68 virtual void OnReceivedResponse( | |
| 69 const ResourceLoaderBridge::ResponseInfo& info, | |
| 70 bool content_filtered) { | |
| 71 response_headers_ = info.headers; | |
| 72 plugin_->functions().response_funcs->start_completed( | |
| 73 cprequest_.get(), CPERR_SUCCESS); | |
| 74 } | |
| 75 | |
| 76 virtual void OnReceivedData(const char* data, int len) { | |
| 77 response_data_.append(data, len); | |
| 78 if (read_buffer_) { | |
| 79 // If we had an asynchronous operation pending, read into that buffer | |
| 80 // and inform the plugin. | |
| 81 int rv = Read(read_buffer_, read_buffer_size_); | |
| 82 DCHECK(rv != CPERR_IO_PENDING); | |
| 83 read_buffer_ = NULL; | |
| 84 plugin_->functions().response_funcs->read_completed( | |
| 85 cprequest_.get(), rv); | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 virtual void OnCompletedRequest(const URLRequestStatus& status, | |
| 90 const std::string& security_info) { | |
| 91 completed_ = true; | |
| 92 | |
| 93 if (!status.is_success()) { | |
| 94 // TODO(mpcomplete): better error codes | |
| 95 // Inform the plugin, calling the right function depending on whether | |
| 96 // we got the start_completed event or not. | |
| 97 if (response_headers_) { | |
| 98 plugin_->functions().response_funcs->start_completed( | |
| 99 cprequest_.get(), CPERR_FAILURE); | |
| 100 } else { | |
| 101 plugin_->functions().response_funcs->read_completed( | |
| 102 cprequest_.get(), CPERR_FAILURE); | |
| 103 } | |
| 104 } else if (read_buffer_) { | |
| 105 // The plugin was waiting for more data. Inform him we're done. | |
| 106 read_buffer_ = NULL; | |
| 107 plugin_->functions().response_funcs->read_completed( | |
| 108 cprequest_.get(), CPERR_SUCCESS); | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 virtual std::string GetURLForDebugging() { | |
| 113 return cprequest_->url; | |
| 114 } | |
| 115 | |
| 116 void set_extra_headers(const std::string& headers) { | |
| 117 extra_headers_ = headers; | |
| 118 } | |
| 119 void set_load_flags(uint32 flags) { | |
| 120 load_flags_ = flags; | |
| 121 } | |
| 122 void set_sync(bool sync) { | |
| 123 sync_ = sync; | |
| 124 } | |
| 125 void AppendDataToUpload(const char* bytes, int bytes_len) { | |
| 126 upload_content_.push_back(net::UploadData::Element()); | |
| 127 upload_content_.back().SetToBytes(bytes, bytes_len); | |
| 128 } | |
| 129 | |
| 130 void AppendFileToUpload(const std::wstring &filepath) { | |
| 131 AppendFileRangeToUpload(filepath, 0, kuint64max); | |
| 132 } | |
| 133 | |
| 134 void AppendFileRangeToUpload(const std::wstring &filepath, | |
| 135 uint64 offset, uint64 length) { | |
| 136 upload_content_.push_back(net::UploadData::Element()); | |
| 137 upload_content_.back().SetToFilePathRange(filepath, offset, length); | |
| 138 } | |
| 139 | |
| 140 CPError Start() { | |
| 141 bridge_.reset( | |
| 142 webkit_glue::ResourceLoaderBridge::Create( | |
| 143 webframe_, | |
| 144 cprequest_->method, | |
| 145 GURL(cprequest_->url), | |
| 146 GURL(cprequest_->url), // TODO(jackson): policy url? | |
| 147 GURL(), // TODO(mpcomplete): referrer? | |
| 148 extra_headers_, | |
| 149 load_flags_, | |
| 150 GetCurrentProcessId(), | |
| 151 ResourceType::OBJECT, | |
| 152 false)); // TODO (jcampan): mixed-content? | |
| 153 if (!bridge_.get()) | |
| 154 return CPERR_FAILURE; | |
| 155 | |
| 156 for (size_t i = 0; i < upload_content_.size(); ++i) { | |
| 157 switch (upload_content_[i].type()) { | |
| 158 case net::UploadData::TYPE_BYTES: { | |
| 159 const std::vector<char>& bytes = upload_content_[i].bytes(); | |
| 160 bridge_->AppendDataToUpload(&bytes[0], | |
| 161 static_cast<int>(bytes.size())); | |
| 162 break; | |
| 163 } | |
| 164 case net::UploadData::TYPE_FILE: { | |
| 165 bridge_->AppendFileRangeToUpload( | |
| 166 upload_content_[i].file_path(), | |
| 167 upload_content_[i].file_range_offset(), | |
| 168 upload_content_[i].file_range_length()); | |
| 169 break; | |
| 170 } | |
| 171 default: { | |
| 172 NOTREACHED() << "Unknown UploadData::Element type"; | |
| 173 } | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 if (sync_) { | |
| 178 ResourceLoaderBridge::SyncLoadResponse response; | |
| 179 bridge_->SyncLoad(&response); | |
| 180 response_headers_ = response.headers; | |
| 181 response_data_ = response.data; | |
| 182 completed_ = true; | |
| 183 return response.status.is_success() ? CPERR_SUCCESS : CPERR_FAILURE; | |
| 184 } else { | |
| 185 if (!bridge_->Start(this)) { | |
| 186 bridge_.reset(); | |
| 187 return CPERR_FAILURE; | |
| 188 } | |
| 189 return CPERR_IO_PENDING; | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 int GetResponseInfo(CPResponseInfoType type, void* buf, uint32 buf_size) { | |
| 194 return PluginResponseUtils::GetResponseInfo( | |
| 195 response_headers_, type, buf, buf_size); | |
| 196 } | |
| 197 | |
| 198 int Read(void* buf, uint32 buf_size) { | |
| 199 uint32 avail = | |
| 200 static_cast<uint32>(response_data_.size()) - response_data_offset_; | |
| 201 uint32 count = buf_size; | |
| 202 if (count > avail) | |
| 203 count = avail; | |
| 204 | |
| 205 int rv = CPERR_FAILURE; | |
| 206 if (count) { | |
| 207 // Data is ready now. | |
| 208 memcpy(buf, &response_data_[0] + response_data_offset_, count); | |
| 209 response_data_offset_ += count; | |
| 210 } else if (!completed_) { | |
| 211 read_buffer_ = buf; | |
| 212 read_buffer_size_ = buf_size; | |
| 213 DCHECK(!sync_); | |
| 214 return CPERR_IO_PENDING; | |
| 215 } | |
| 216 | |
| 217 if (response_data_.size() == response_data_offset_) { | |
| 218 // Simple optimization for large requests. Generally the consumer will | |
| 219 // read the data faster than it comes in, so we can clear our buffer | |
| 220 // any time it has all been read. | |
| 221 response_data_.clear(); | |
| 222 response_data_offset_ = 0; | |
| 223 } | |
| 224 | |
| 225 read_buffer_ = NULL; | |
| 226 return count; | |
| 227 } | |
| 228 | |
| 229 private: | |
| 230 scoped_ptr<ScopableCPRequest> cprequest_; | |
| 231 WebFrame* webframe_; | |
| 232 scoped_ptr<ResourceLoaderBridge> bridge_; | |
| 233 std::vector<net::UploadData::Element> upload_content_; | |
| 234 std::string extra_headers_; | |
| 235 uint32 load_flags_; | |
| 236 bool sync_; | |
| 237 | |
| 238 scoped_refptr<net::HttpResponseHeaders> response_headers_; | |
| 239 std::string response_data_; | |
| 240 int response_data_offset_; | |
| 241 bool completed_; | |
| 242 void* read_buffer_; | |
| 243 uint32 read_buffer_size_; | |
| 244 }; | |
| 245 | |
| 246 // | |
| 247 // Generic functions | |
| 248 // | |
| 249 | |
| 250 // TODO(mpcomplete): call up to browser to ask for a valid browsing context. | |
| 251 WebPlugin* WebPluginFromContext(CPBrowsingContext context) { | |
| 252 return reinterpret_cast<WebPlugin*>(static_cast<LONG_PTR>(context)); | |
| 253 } | |
| 254 | |
| 255 CPBrowsingContext ContextFromWebPlugin(WebPlugin* webplugin) { | |
| 256 return static_cast<CPBrowsingContext>(reinterpret_cast<LONG_PTR>(webplugin)); | |
| 257 } | |
| 258 | |
| 259 void STDCALL CPB_SetKeepProcessAlive(CPID id, CPBool keep_alive) { | |
| 260 // Doesn't apply in the renderer process. | |
| 261 } | |
| 262 | |
| 263 CPError STDCALL CPB_GetCookies(CPID id, CPBrowsingContext context, | |
| 264 const char* url, char** cookies) { | |
| 265 CHECK(ChromePluginLib::IsPluginThread()); | |
| 266 | |
| 267 std::string cookies_str; | |
| 268 RenderThread::current()->Send( | |
| 269 new ViewHostMsg_GetCookies(GURL(url), GURL(url), &cookies_str)); | |
| 270 | |
| 271 *cookies = CPB_StringDup(CPB_Alloc, cookies_str); | |
| 272 return CPERR_SUCCESS; | |
| 273 } | |
| 274 | |
| 275 CPError STDCALL CPB_ShowHtmlDialogModal( | |
| 276 CPID id, CPBrowsingContext context, const char* url, int width, int height, | |
| 277 const char* json_arguments, char** json_retval) { | |
| 278 CHECK(ChromePluginLib::IsPluginThread()); | |
| 279 | |
| 280 WebPlugin* webplugin = WebPluginFromContext(context); | |
| 281 if (!webplugin) | |
| 282 return CPERR_INVALID_PARAMETER; | |
| 283 | |
| 284 std::string retval_str; | |
| 285 webplugin->ShowModalHTMLDialog( | |
| 286 GURL(url), width, height, json_arguments, &retval_str); | |
| 287 *json_retval = CPB_StringDup(CPB_Alloc, retval_str); | |
| 288 return CPERR_SUCCESS; | |
| 289 } | |
| 290 | |
| 291 CPError STDCALL CPB_ShowHtmlDialog( | |
| 292 CPID id, CPBrowsingContext context, const char* url, int width, int height, | |
| 293 const char* json_arguments, void* plugin_context) { | |
| 294 // TODO(mpcomplete): support non-modal dialogs. | |
| 295 return CPERR_FAILURE; | |
| 296 } | |
| 297 | |
| 298 CPError STDCALL CPB_GetCommandLineArguments( | |
| 299 CPID id, CPBrowsingContext context, const char* url, char** arguments) { | |
| 300 CHECK(ChromePluginLib::IsPluginThread()); | |
| 301 std::string arguments_str; | |
| 302 CPError rv = CPB_GetCommandLineArgumentsCommon(url, &arguments_str); | |
| 303 if (rv == CPERR_SUCCESS) | |
| 304 *arguments = CPB_StringDup(CPB_Alloc, arguments_str); | |
| 305 return rv; | |
| 306 } | |
| 307 | |
| 308 CPBrowsingContext STDCALL CPB_GetBrowsingContextFromNPP(NPP npp) { | |
| 309 if (!npp) | |
| 310 return CPERR_INVALID_PARAMETER; | |
| 311 | |
| 312 NPAPI::PluginInstance* instance = | |
| 313 static_cast<NPAPI::PluginInstance *>(npp->ndata); | |
| 314 return ContextFromWebPlugin(instance->webplugin()); | |
| 315 } | |
| 316 | |
| 317 int STDCALL CPB_GetBrowsingContextInfo( | |
| 318 CPID id, CPBrowsingContext context, CPBrowsingContextInfoType type, | |
| 319 void* buf, uint32 buf_size) { | |
| 320 CHECK(ChromePluginLib::IsPluginThread()); | |
| 321 | |
| 322 switch (type) { | |
| 323 case CPBROWSINGCONTEXT_DATA_DIR_PTR: { | |
| 324 if (buf_size < sizeof(char*)) | |
| 325 return sizeof(char*); | |
| 326 | |
| 327 std::wstring wretval; | |
| 328 if (!RenderThread::current()->Send(new ViewHostMsg_GetDataDir(&wretval))) | |
| 329 return CPERR_FAILURE; | |
| 330 file_util::AppendToPath(&wretval, chrome::kChromePluginDataDirname); | |
| 331 *static_cast<char**>(buf) = CPB_StringDup(CPB_Alloc, WideToUTF8(wretval)); | |
| 332 return CPERR_SUCCESS; | |
| 333 } | |
| 334 case CPBROWSINGCONTEXT_UI_LOCALE_PTR: { | |
| 335 if (buf_size < sizeof(char*)) | |
| 336 return sizeof(char*); | |
| 337 | |
| 338 std::wstring wretval = webkit_glue::GetWebKitLocale(); | |
| 339 *static_cast<char**>(buf) = CPB_StringDup(CPB_Alloc, WideToUTF8(wretval)); | |
| 340 return CPERR_SUCCESS; | |
| 341 } | |
| 342 } | |
| 343 | |
| 344 return CPERR_FAILURE; | |
| 345 } | |
| 346 | |
| 347 CPError STDCALL CPB_AddUICommand(CPID id, int command) { | |
| 348 // Not implemented in the renderer process | |
| 349 return CPERR_FAILURE; | |
| 350 } | |
| 351 | |
| 352 CPError STDCALL CPB_HandleCommand( | |
| 353 CPID id, CPBrowsingContext context, int command, void *data) { | |
| 354 // Not implemented in the renderer process | |
| 355 return CPERR_FAILURE; | |
| 356 } | |
| 357 | |
| 358 // | |
| 359 // Functions related to network interception | |
| 360 // | |
| 361 | |
| 362 void STDCALL CPB_EnableRequestIntercept( | |
| 363 CPID id, const char** schemes, uint32 num_schemes) { | |
| 364 // We ignore requests by the plugin to intercept from this process. That's | |
| 365 // handled in the browser process. | |
| 366 } | |
| 367 | |
| 368 void STDCALL CPRR_ReceivedRedirect(CPRequest* request, const char* new_url) { | |
| 369 NOTREACHED() << "Network interception should not happen in renderer process."; | |
| 370 } | |
| 371 | |
| 372 void STDCALL CPRR_StartCompleted(CPRequest* request, CPError result) { | |
| 373 NOTREACHED() << "Network interception should not happen in renderer process."; | |
| 374 } | |
| 375 | |
| 376 void STDCALL CPRR_ReadCompleted(CPRequest* request, int bytes_read) { | |
| 377 NOTREACHED() << "Network interception should not happen in renderer process."; | |
| 378 } | |
| 379 | |
| 380 void STDCALL CPRR_UploadProgress(CPRequest* request, uint64 pos, uint64 size) { | |
| 381 NOTREACHED() << "Network interception should not happen in renderer process."; | |
| 382 } | |
| 383 | |
| 384 // | |
| 385 // Functions related to serving network requests to the plugin | |
| 386 // | |
| 387 | |
| 388 CPError STDCALL CPB_CreateRequest(CPID id, CPBrowsingContext context, | |
| 389 const char* method, const char* url, | |
| 390 CPRequest** request) { | |
| 391 CHECK(ChromePluginLib::IsPluginThread()); | |
| 392 ChromePluginLib* plugin = ChromePluginLib::FromCPID(id); | |
| 393 CHECK(plugin); | |
| 394 | |
| 395 WebPlugin* webplugin = WebPluginFromContext(context); | |
| 396 WebFrame* webframe = webplugin->GetWebFrame(); | |
| 397 ScopableCPRequest* cprequest = new ScopableCPRequest(url, method, context); | |
| 398 PluginRequestHandlerProxy* handler = | |
| 399 new PluginRequestHandlerProxy(plugin, cprequest, webframe); | |
| 400 | |
| 401 *request = cprequest; | |
| 402 return CPERR_SUCCESS; | |
| 403 } | |
| 404 | |
| 405 CPError STDCALL CPR_StartRequest(CPRequest* request) { | |
| 406 CHECK(ChromePluginLib::IsPluginThread()); | |
| 407 PluginRequestHandlerProxy* handler = | |
| 408 PluginRequestHandlerProxy::FromCPRequest(request); | |
| 409 CHECK(handler); | |
| 410 return handler->Start(); | |
| 411 } | |
| 412 | |
| 413 void STDCALL CPR_EndRequest(CPRequest* request, CPError reason) { | |
| 414 CHECK(ChromePluginLib::IsPluginThread()); | |
| 415 PluginRequestHandlerProxy* handler = | |
| 416 PluginRequestHandlerProxy::FromCPRequest(request); | |
| 417 delete handler; | |
| 418 } | |
| 419 | |
| 420 void STDCALL CPR_SetExtraRequestHeaders(CPRequest* request, | |
| 421 const char* headers) { | |
| 422 CHECK(ChromePluginLib::IsPluginThread()); | |
| 423 PluginRequestHandlerProxy* handler = | |
| 424 PluginRequestHandlerProxy::FromCPRequest(request); | |
| 425 CHECK(handler); | |
| 426 handler->set_extra_headers(headers); | |
| 427 } | |
| 428 | |
| 429 void STDCALL CPR_SetRequestLoadFlags(CPRequest* request, uint32 flags) { | |
| 430 CHECK(ChromePluginLib::IsPluginThread()); | |
| 431 PluginRequestHandlerProxy* handler = | |
| 432 PluginRequestHandlerProxy::FromCPRequest(request); | |
| 433 CHECK(handler); | |
| 434 | |
| 435 if (flags & CPREQUESTLOAD_SYNCHRONOUS) { | |
| 436 handler->set_sync(true); | |
| 437 } | |
| 438 | |
| 439 uint32 net_flags = PluginResponseUtils::CPLoadFlagsToNetFlags(flags); | |
| 440 handler->set_load_flags(net_flags); | |
| 441 } | |
| 442 | |
| 443 void STDCALL CPR_AppendDataToUpload(CPRequest* request, const char* bytes, | |
| 444 int bytes_len) { | |
| 445 CHECK(ChromePluginLib::IsPluginThread()); | |
| 446 PluginRequestHandlerProxy* handler = | |
| 447 PluginRequestHandlerProxy::FromCPRequest(request); | |
| 448 CHECK(handler); | |
| 449 handler->AppendDataToUpload(bytes, bytes_len); | |
| 450 } | |
| 451 | |
| 452 CPError STDCALL CPR_AppendFileToUpload(CPRequest* request, const char* filepath, | |
| 453 uint64 offset, uint64 length) { | |
| 454 CHECK(ChromePluginLib::IsPluginThread()); | |
| 455 PluginRequestHandlerProxy* handler = | |
| 456 PluginRequestHandlerProxy::FromCPRequest(request); | |
| 457 CHECK(handler); | |
| 458 | |
| 459 if (!length) length = kuint64max; | |
| 460 std::wstring wfilepath(UTF8ToWide(filepath)); | |
| 461 handler->AppendFileRangeToUpload(wfilepath, offset, length); | |
| 462 return CPERR_SUCCESS; | |
| 463 } | |
| 464 | |
| 465 int STDCALL CPR_GetResponseInfo(CPRequest* request, CPResponseInfoType type, | |
| 466 void* buf, uint32 buf_size) { | |
| 467 CHECK(ChromePluginLib::IsPluginThread()); | |
| 468 PluginRequestHandlerProxy* handler = | |
| 469 PluginRequestHandlerProxy::FromCPRequest(request); | |
| 470 CHECK(handler); | |
| 471 return handler->GetResponseInfo(type, buf, buf_size); | |
| 472 } | |
| 473 | |
| 474 int STDCALL CPR_Read(CPRequest* request, void* buf, uint32 buf_size) { | |
| 475 CHECK(ChromePluginLib::IsPluginThread()); | |
| 476 PluginRequestHandlerProxy* handler = | |
| 477 PluginRequestHandlerProxy::FromCPRequest(request); | |
| 478 CHECK(handler); | |
| 479 return handler->Read(buf, buf_size); | |
| 480 } | |
| 481 | |
| 482 CPBool STDCALL CPB_IsPluginProcessRunning(CPID id) { | |
| 483 CHECK(ChromePluginLib::IsPluginThread()); | |
| 484 return true; | |
| 485 } | |
| 486 | |
| 487 CPProcessType STDCALL CPB_GetProcessType(CPID id) { | |
| 488 CHECK(ChromePluginLib::IsPluginThread()); | |
| 489 return CP_PROCESS_RENDERER; | |
| 490 } | |
| 491 | |
| 492 CPError STDCALL CPB_SendMessage(CPID id, const void *data, uint32 data_len) { | |
| 493 CHECK(ChromePluginLib::IsPluginThread()); | |
| 494 ChromePluginLib* plugin = ChromePluginLib::FromCPID(id); | |
| 495 CHECK(plugin); | |
| 496 | |
| 497 const uint8* data_ptr = static_cast<const uint8*>(data); | |
| 498 std::vector<uint8> v(data_ptr, data_ptr + data_len); | |
| 499 if (!RenderThread::current()->Send( | |
| 500 new ViewHostMsg_PluginMessage(plugin->filename(), v))) { | |
| 501 return CPERR_FAILURE; | |
| 502 } | |
| 503 return CPERR_SUCCESS; | |
| 504 } | |
| 505 | |
| 506 CPError STDCALL CPB_SendSyncMessage(CPID id, const void *data, uint32 data_len, | |
| 507 void **retval, uint32 *retval_len) { | |
| 508 CHECK(ChromePluginLib::IsPluginThread()); | |
| 509 ChromePluginLib* plugin = ChromePluginLib::FromCPID(id); | |
| 510 CHECK(plugin); | |
| 511 | |
| 512 const uint8* data_ptr = static_cast<const uint8*>(data); | |
| 513 std::vector<uint8> v(data_ptr, data_ptr + data_len); | |
| 514 std::vector<uint8> r; | |
| 515 if (!RenderThread::current()->Send(new ViewHostMsg_PluginSyncMessage( | |
| 516 plugin->filename(), v, &r))) { | |
| 517 return CPERR_FAILURE; | |
| 518 } | |
| 519 | |
| 520 if (r.size()) { | |
| 521 *retval_len = static_cast<uint32>(r.size()); | |
| 522 *retval = CPB_Alloc(*retval_len); | |
| 523 memcpy(*retval, &(r.at(0)), r.size()); | |
| 524 } else { | |
| 525 *retval = NULL; | |
| 526 *retval_len = 0; | |
| 527 } | |
| 528 | |
| 529 return CPERR_SUCCESS; | |
| 530 } | |
| 531 | |
| 532 CPError STDCALL CPB_PluginThreadAsyncCall(CPID id, | |
| 533 void (*func)(void *), | |
| 534 void *user_data) { | |
| 535 MessageLoop *message_loop = ChromePluginLib::GetPluginThreadLoop(); | |
| 536 if (!message_loop) { | |
| 537 return CPERR_FAILURE; | |
| 538 } | |
| 539 message_loop->PostTask(FROM_HERE, NewRunnableFunction(func, user_data)); | |
| 540 | |
| 541 return CPERR_SUCCESS; | |
| 542 } | |
| 543 | |
| 544 class PluginOpenFileDialogListener : public WebFileChooserCallback { | |
| 545 public: | |
| 546 PluginOpenFileDialogListener(CPID cpid, void *user_data) | |
| 547 : cpid_(cpid), user_data_(user_data) { | |
| 548 } | |
| 549 virtual void OnFileChoose(const std::vector<std::wstring>& file_names) { | |
| 550 ChromePluginLib *chrome_plugin = ChromePluginLib::FromCPID(cpid_); | |
| 551 if (chrome_plugin) { | |
| 552 if (!file_names.empty()) { | |
| 553 std::vector<std::string> utf8_files; | |
| 554 std::vector<const char *> ret_files; | |
| 555 for (std::vector<std::wstring>::const_iterator ix = file_names.begin(); | |
| 556 ix != file_names.end(); ++ix) { | |
| 557 utf8_files.push_back(WideToUTF8(*ix)); | |
| 558 ret_files.push_back(utf8_files.back().c_str()); | |
| 559 } | |
| 560 | |
| 561 chrome_plugin->functions().on_file_dialog_result(user_data_, | |
| 562 &ret_files.at(0), | |
| 563 ret_files.size()); | |
| 564 } else { | |
| 565 chrome_plugin->functions().on_file_dialog_result(user_data_, 0, 0); | |
| 566 } | |
| 567 } | |
| 568 } | |
| 569 | |
| 570 private: | |
| 571 CPID cpid_; | |
| 572 void *user_data_; | |
| 573 }; | |
| 574 | |
| 575 CPError STDCALL CPB_OpenFileDialog(CPID id, | |
| 576 CPBrowsingContext context, | |
| 577 bool multiple_files, | |
| 578 const char *title, | |
| 579 const char *filter, | |
| 580 void *user_data) { | |
| 581 CHECK(ChromePluginLib::IsPluginThread()); | |
| 582 | |
| 583 WebPlugin* webplugin = WebPluginFromContext(context); | |
| 584 WebFrame* webframe = webplugin->GetWebFrame(); | |
| 585 WebView* webview = webframe->GetView(); | |
| 586 WebViewDelegate* webviewdelegate = webview->GetDelegate(); | |
| 587 | |
| 588 PluginOpenFileDialogListener *listener = | |
| 589 new PluginOpenFileDialogListener(id, user_data); | |
| 590 | |
| 591 webviewdelegate->RunFileChooser(multiple_files, UTF8ToWide(title), | |
| 592 std::wstring(), UTF8ToWide(filter), | |
| 593 listener); | |
| 594 | |
| 595 return CPERR_SUCCESS; | |
| 596 } | |
| 597 | |
| 598 } // namespace | |
| 599 | |
| 600 CPBrowserFuncs* GetCPBrowserFuncsForRenderer() { | |
| 601 static CPBrowserFuncs browser_funcs; | |
| 602 static CPRequestFuncs request_funcs; | |
| 603 static CPResponseFuncs response_funcs; | |
| 604 static bool initialized = false; | |
| 605 if (!initialized) { | |
| 606 initialized = true; | |
| 607 | |
| 608 browser_funcs.size = sizeof(browser_funcs); | |
| 609 browser_funcs.version = CP_VERSION; | |
| 610 browser_funcs.enable_request_intercept = CPB_EnableRequestIntercept; | |
| 611 browser_funcs.create_request = CPB_CreateRequest; | |
| 612 browser_funcs.get_cookies = CPB_GetCookies; | |
| 613 browser_funcs.alloc = CPB_Alloc; | |
| 614 browser_funcs.free = CPB_Free; | |
| 615 browser_funcs.set_keep_process_alive = CPB_SetKeepProcessAlive; | |
| 616 browser_funcs.show_html_dialog = CPB_ShowHtmlDialog; | |
| 617 browser_funcs.show_html_dialog_modal = CPB_ShowHtmlDialogModal; | |
| 618 browser_funcs.is_plugin_process_running = CPB_IsPluginProcessRunning; | |
| 619 browser_funcs.get_process_type = CPB_GetProcessType; | |
| 620 browser_funcs.send_message = CPB_SendMessage; | |
| 621 browser_funcs.get_browsing_context_from_npp = CPB_GetBrowsingContextFromNPP; | |
| 622 browser_funcs.get_browsing_context_info = CPB_GetBrowsingContextInfo; | |
| 623 browser_funcs.get_command_line_arguments = CPB_GetCommandLineArguments; | |
| 624 browser_funcs.add_ui_command = CPB_AddUICommand; | |
| 625 browser_funcs.handle_command = CPB_HandleCommand; | |
| 626 browser_funcs.send_sync_message = CPB_SendSyncMessage; | |
| 627 browser_funcs.plugin_thread_async_call = CPB_PluginThreadAsyncCall; | |
| 628 browser_funcs.open_file_dialog = CPB_OpenFileDialog; | |
| 629 | |
| 630 browser_funcs.request_funcs = &request_funcs; | |
| 631 browser_funcs.response_funcs = &response_funcs; | |
| 632 | |
| 633 request_funcs.size = sizeof(request_funcs); | |
| 634 request_funcs.start_request = CPR_StartRequest; | |
| 635 request_funcs.end_request = CPR_EndRequest; | |
| 636 request_funcs.set_extra_request_headers = CPR_SetExtraRequestHeaders; | |
| 637 request_funcs.set_request_load_flags = CPR_SetRequestLoadFlags; | |
| 638 request_funcs.append_data_to_upload = CPR_AppendDataToUpload; | |
| 639 request_funcs.get_response_info = CPR_GetResponseInfo; | |
| 640 request_funcs.read = CPR_Read; | |
| 641 request_funcs.append_file_to_upload = CPR_AppendFileToUpload; | |
| 642 | |
| 643 response_funcs.size = sizeof(response_funcs); | |
| 644 response_funcs.received_redirect = CPRR_ReceivedRedirect; | |
| 645 response_funcs.start_completed = CPRR_StartCompleted; | |
| 646 response_funcs.read_completed = CPRR_ReadCompleted; | |
| 647 response_funcs.upload_progress = CPRR_UploadProgress; | |
| 648 } | |
| 649 | |
| 650 return &browser_funcs; | |
| 651 } | |
| OLD | NEW |