Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(291)

Side by Side Diff: chrome/browser/chrome_plugin_host.cc

Issue 6576020: Remove Gears from Chrome (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: windows fixes Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/chrome_plugin_host.h ('k') | chrome/browser/chrome_plugin_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chrome_plugin_host.h"
6
7 #include <set>
8 #include <string>
9 #include <vector>
10
11 #include "base/basictypes.h"
12 #include "base/command_line.h"
13 #include "base/file_path.h"
14 #include "base/file_util.h"
15 #include "base/message_loop.h"
16 #include "base/metrics/histogram.h"
17 #include "base/path_service.h"
18 #include "base/perftimer.h"
19 #include "base/singleton.h"
20 #include "base/string_util.h"
21 #include "base/utf_string_conversions.h"
22 #include "chrome/browser/browser_list.h"
23 #include "chrome/browser/chrome_plugin_browsing_context.h"
24 #include "chrome/browser/gears_integration.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/ui/webui/html_dialog_ui.h"
27 #include "chrome/common/chrome_constants.h"
28 #include "chrome/common/chrome_counters.h"
29 #include "chrome/common/chrome_paths.h"
30 #include "chrome/common/chrome_plugin_lib.h"
31 #include "chrome/common/chrome_plugin_util.h"
32 #include "chrome/common/gears_api.h"
33 #include "chrome/common/net/url_request_context_getter.h"
34 #include "chrome/common/net/url_request_intercept_job.h"
35 #include "chrome/common/plugin_messages.h"
36 #include "chrome/common/render_messages.h"
37 #include "content/browser/browser_thread.h"
38 #include "content/browser/plugin_process_host.h"
39 #include "content/browser/plugin_service.h"
40 #include "content/browser/renderer_host/render_process_host.h"
41 #include "content/common/notification_service.h"
42 #include "net/base/cookie_monster.h"
43 #include "net/base/io_buffer.h"
44 #include "net/base/net_errors.h"
45 #include "net/http/http_request_headers.h"
46 #include "net/url_request/url_request.h"
47 #include "net/url_request/url_request_context.h"
48 #include "net/url_request/url_request_error_job.h"
49 #include "third_party/skia/include/core/SkBitmap.h"
50
51
52 using base::TimeDelta;
53
54 // This class manages the interception of network requests. It queries the
55 // plugin on every request, and creates an intercept job if the plugin can
56 // intercept the request.
57 // NOTE: All methods must be called on the IO thread.
58 class PluginRequestInterceptor
59 : public PluginHelper, public net::URLRequest::Interceptor {
60 public:
61 static net::URLRequestJob* UninterceptedProtocolHandler(
62 net::URLRequest* request, const std::string& scheme) {
63 // This will get called if a plugin failed to intercept a request for a
64 // protocol it has registered. In that case, we return NULL and the request
65 // will result in an error.
66 return new net::URLRequestErrorJob(request, net::ERR_FILE_NOT_FOUND);
67 }
68
69 explicit PluginRequestInterceptor(ChromePluginLib* plugin)
70 : PluginHelper(plugin) {
71 net::URLRequest::RegisterRequestInterceptor(this);
72 }
73
74 virtual ~PluginRequestInterceptor() {
75 net::URLRequest::UnregisterRequestInterceptor(this);
76
77 // Unregister our protocols.
78 for (HandledProtocolList::iterator it = registered_protocols_.begin();
79 it != registered_protocols_.end(); ++it) {
80 net::URLRequest::ProtocolFactory* factory =
81 net::URLRequest::RegisterProtocolFactory(*it, NULL);
82 DCHECK(factory == UninterceptedProtocolHandler);
83 }
84 }
85
86 void RegisterProtocol(const std::string& scheme) {
87 DCHECK(CalledOnValidThread());
88
89 std::string lower_scheme = StringToLowerASCII(scheme);
90 handled_protocols_.insert(lower_scheme);
91
92 // Only add a protocol factory if the net::URLRequest doesn't already handle
93 // it. If we fail to intercept, the request will be treated as an error.
94 if (!net::URLRequest::IsHandledProtocol(lower_scheme)) {
95 registered_protocols_.insert(lower_scheme);
96 net::URLRequest::RegisterProtocolFactory(lower_scheme,
97 &UninterceptedProtocolHandler);
98 }
99 }
100
101 // net::URLRequest::Interceptor
102 virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request) {
103 // TODO(darin): This DCHECK fails in the unit tests because our interceptor
104 // is being persisted across unit tests. As a result, each time we get
105 // poked on a different thread, but never from more than one thread at a
106 // time. We need a way to have the URLRequestJobManager get reset between
107 // unit tests.
108 // DCHECK(CalledOnValidThread());
109
110 if (!IsHandledProtocol(request->url().scheme()))
111 return NULL;
112
113 CPBrowsingContext context =
114 CPBrowsingContextManager::GetInstance()->Lookup(request->context());
115 scoped_ptr<ScopableCPRequest> cprequest(
116 new ScopableCPRequest(request->url().spec().c_str(),
117 request->method().c_str(),
118 context));
119
120 PerfTimer timer;
121 if (!plugin_->functions().should_intercept_request(cprequest.get())) {
122 LogInterceptMissTime(timer.Elapsed());
123 return NULL;
124 }
125 LogInterceptHitTime(timer.Elapsed());
126 return new URLRequestInterceptJob(request, plugin_, cprequest.release());
127 }
128
129 private:
130 bool IsHandledProtocol(const std::string& scheme) {
131 return handled_protocols_.find(scheme) != handled_protocols_.end();
132 }
133
134 void LogInterceptHitTime(const TimeDelta& time) {
135 UMA_HISTOGRAM_TIMES("Gears.InterceptHit", time);
136 }
137
138 void LogInterceptMissTime(const TimeDelta& time) {
139 UMA_HISTOGRAM_TIMES("Gears.InterceptMiss", time);
140 }
141
142 typedef std::set<std::string> HandledProtocolList;
143 HandledProtocolList handled_protocols_;
144 HandledProtocolList registered_protocols_;
145 };
146
147 // This class manages a network request made by the plugin, also acting as
148 // the net::URLRequest delegate.
149 // NOTE: All methods must be called on the IO thread.
150 class PluginRequestHandler : public PluginHelper,
151 public net::URLRequest::Delegate {
152 public:
153 static PluginRequestHandler* FromCPRequest(CPRequest* request) {
154 return ScopableCPRequest::GetData<PluginRequestHandler*>(request);
155 }
156
157 PluginRequestHandler(ChromePluginLib* plugin, ScopableCPRequest* cprequest)
158 : PluginHelper(plugin), cprequest_(cprequest), user_buffer_(NULL) {
159 cprequest_->data = this; // see FromCPRequest().
160
161 net::URLRequestContext* context = CPBrowsingContextManager::GetInstance()->
162 ToURLRequestContext(cprequest_->context);
163 // TODO(mpcomplete): remove fallback case when Gears support is prevalent.
164 if (!context)
165 context = Profile::GetDefaultRequestContext()->GetURLRequestContext();
166
167 GURL gurl(cprequest_->url);
168 request_.reset(new net::URLRequest(gurl, this));
169 request_->set_context(context);
170 request_->set_method(cprequest_->method);
171 request_->set_load_flags(PluginResponseUtils::CPLoadFlagsToNetFlags(0));
172 }
173
174 net::URLRequest* request() { return request_.get(); }
175
176 // Wraper of net::URLRequest::Read()
177 bool Read(char* dest, int dest_size, int *bytes_read) {
178 CHECK(!my_buffer_.get());
179 // We'll use our own buffer until the read actually completes.
180 user_buffer_ = dest;
181 my_buffer_ = new net::IOBuffer(dest_size);
182
183 if (request_->Read(my_buffer_, dest_size, bytes_read)) {
184 memcpy(dest, my_buffer_->data(), *bytes_read);
185 my_buffer_ = NULL;
186 return true;
187 }
188
189 if (!request_->status().is_io_pending())
190 my_buffer_ = NULL;
191
192 return false;
193 }
194
195 // net::URLRequest::Delegate
196 virtual void OnReceivedRedirect(net::URLRequest* request, const GURL& new_url,
197 bool* defer_redirect) {
198 plugin_->functions().response_funcs->received_redirect(
199 cprequest_.get(), new_url.spec().c_str());
200 }
201
202 virtual void OnResponseStarted(net::URLRequest* request) {
203 // TODO(mpcomplete): better error codes
204 CPError result =
205 request_->status().is_success() ? CPERR_SUCCESS : CPERR_FAILURE;
206 plugin_->functions().response_funcs->start_completed(
207 cprequest_.get(), result);
208 }
209
210 virtual void OnReadCompleted(net::URLRequest* request, int bytes_read) {
211 CHECK(my_buffer_.get());
212 CHECK(user_buffer_);
213 if (bytes_read > 0) {
214 memcpy(user_buffer_, my_buffer_->data(), bytes_read);
215 } else if (bytes_read < 0) {
216 // TODO(mpcomplete): better error codes
217 bytes_read = CPERR_FAILURE;
218 }
219 my_buffer_ = NULL;
220 plugin_->functions().response_funcs->read_completed(
221 cprequest_.get(), bytes_read);
222 }
223
224 private:
225 scoped_ptr<ScopableCPRequest> cprequest_;
226 scoped_ptr<net::URLRequest> request_;
227 scoped_refptr<net::IOBuffer> my_buffer_;
228 char* user_buffer_;
229 };
230
231 // This class manages plugins that want to handle UI commands. Right now, we
232 // only allow 1 plugin to do this, so there's only ever 1 instance of this
233 // class at once.
234 // NOTE: All methods must be called on the IO thread.
235 class PluginCommandHandler : public PluginHelper {
236 public:
237 static void HandleCommand(int command,
238 CPCommandInterface* data,
239 int32 context_as_int32) {
240 CPBrowsingContext context =
241 static_cast<CPBrowsingContext>(context_as_int32);
242 // Ensure plugins are loaded before we try to talk to it. This will be a
243 // noop if plugins are loaded already.
244 ChromePluginLib::LoadChromePlugins(GetCPBrowserFuncsForBrowser());
245
246 DCHECK(ChromePluginLib::IsPluginThread());
247 CPError rv = CPERR_INVALID_VERSION;
248 if (instance_ && instance_->plugin_->functions().handle_command) {
249 rv = instance_->plugin_->functions().handle_command(
250 context, command, data ? data->GetData() : NULL);
251 }
252 if (data)
253 data->OnCommandInvoked(rv);
254 }
255
256 static void RegisterPlugin(ChromePluginLib* plugin) {
257 DCHECK(ChromePluginLib::IsPluginThread());
258 // TODO(mpcomplete): We only expect to have Gears register a command handler
259 // at the moment. We should either add support for other plugins to do
260 // this, or verify that the plugin is Gears.
261 DCHECK(!instance_) <<
262 "We only support a single plugin handling UI commands.";
263 if (instance_)
264 return;
265 // Deleted in response to a notification in PluginHelper.
266 new PluginCommandHandler(plugin);
267 }
268
269 private:
270 explicit PluginCommandHandler(ChromePluginLib* plugin)
271 : PluginHelper(plugin) {
272 DCHECK(instance_ == NULL);
273 instance_ = this;
274 }
275
276 virtual ~PluginCommandHandler() {
277 instance_ = NULL;
278 }
279
280 static PluginCommandHandler* instance_;
281 };
282
283 PluginCommandHandler* PluginCommandHandler::instance_ = NULL;
284
285 // This class acts as a helper to display the HTML dialog. It is created
286 // on demand on the plugin thread, and proxies calls to and from the UI thread
287 // to display the UI.
288 class ModelessHtmlDialogDelegate : public HtmlDialogUIDelegate {
289 public:
290 ModelessHtmlDialogDelegate(const GURL& url,
291 int width, int height,
292 const std::string& json_arguments,
293 void* plugin_context,
294 ChromePluginLib* plugin,
295 MessageLoop* main_message_loop,
296 gfx::NativeWindow parent_wnd)
297 : main_message_loop_(main_message_loop),
298 io_message_loop_(MessageLoop::current()),
299 plugin_(plugin),
300 plugin_context_(plugin_context),
301 parent_wnd_(parent_wnd) {
302 DCHECK(ChromePluginLib::IsPluginThread());
303 params_.url = url;
304 params_.height = height;
305 params_.width = width;
306 params_.json_input = json_arguments;
307
308 main_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
309 this, &ModelessHtmlDialogDelegate::Show));
310 }
311 virtual ~ModelessHtmlDialogDelegate() {
312 DCHECK(ChromePluginLib::IsPluginThread());
313 }
314
315 // The following public methods are called from the UI thread.
316
317 // HtmlDialogUIDelegate implementation:
318 virtual bool IsDialogModal() const { return false; }
319 virtual std::wstring GetDialogTitle() const { return L"Gears"; }
320 virtual GURL GetDialogContentURL() const { return params_.url; }
321 virtual void GetWebUIMessageHandlers(
322 std::vector<WebUIMessageHandler*>* handlers) const {}
323 virtual void GetDialogSize(gfx::Size* size) const {
324 size->set_width(params_.width);
325 size->set_height(params_.height);
326 }
327 virtual std::string GetDialogArgs() const { return params_.json_input; }
328 virtual void OnDialogClosed(const std::string& json_retval) {
329 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
330 this, &ModelessHtmlDialogDelegate::ReportResults, json_retval));
331 }
332 virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) { }
333 virtual bool ShouldShowDialogTitle() const { return true; }
334
335 private:
336 // Actually shows the dialog on the UI thread.
337 void Show() {
338 DCHECK(MessageLoop::current() == main_message_loop_);
339 Browser* browser = BrowserList::GetLastActive();
340 browser->BrowserShowHtmlDialog(this, parent_wnd_);
341 }
342
343 // Gives the JSON result string back to the plugin.
344 void ReportResults(const std::string& json_retval) {
345 DCHECK(MessageLoop::current() == io_message_loop_);
346 // The plugin may have unloaded before it was time to report the results.
347 if (plugin_->is_loaded())
348 plugin_->functions().html_dialog_closed(plugin_context_,
349 json_retval.c_str());
350 delete this;
351 }
352
353 // The parameters needed to display a modal HTML dialog.
354 HtmlDialogUI::HtmlDialogParams params_;
355
356 // Message loops for sending messages between UI and IO threads.
357 MessageLoop* main_message_loop_;
358 MessageLoop* io_message_loop_;
359
360 // The plugin object that requested the dialog. This can only be accessed on
361 // the IO thread.
362 scoped_refptr<ChromePluginLib> plugin_;
363
364 // The plugin's context argument to CPB_ShowHtmlDialog.
365 void* plugin_context_;
366
367 // The window this dialog box should be parented to, or NULL for the last
368 // active browser window.
369 gfx::NativeWindow parent_wnd_;
370
371 DISALLOW_COPY_AND_ASSIGN(ModelessHtmlDialogDelegate);
372 };
373
374 // Allows InvokeLater without adding refcounting. The object is only deleted
375 // when its last InvokeLater is run anyway.
376 DISABLE_RUNNABLE_METHOD_REFCOUNT(ModelessHtmlDialogDelegate);
377
378 namespace {
379
380 //
381 // Generic functions
382 //
383
384 void STDCALL CPB_SetKeepProcessAlive(CPID id, CPBool keep_alive) {
385 // This is a no-op in the main browser process
386 }
387
388 CPError STDCALL CPB_GetCookies(CPID id, CPBrowsingContext bcontext,
389 const char* url, char** cookies) {
390 CHECK(ChromePluginLib::IsPluginThread());
391 net::URLRequestContext* context = CPBrowsingContextManager::GetInstance()->
392 ToURLRequestContext(bcontext);
393 // TODO(mpcomplete): remove fallback case when Gears support is prevalent.
394 if (!context) {
395 context = Profile::GetDefaultRequestContext()->GetURLRequestContext();
396 if (!context)
397 return CPERR_FAILURE;
398 }
399 std::string cookies_str = context->cookie_store()->GetCookies(GURL(url));
400 *cookies = CPB_StringDup(CPB_Alloc, cookies_str);
401 return CPERR_SUCCESS;
402 }
403
404 CPError STDCALL CPB_ShowHtmlDialogModal(
405 CPID id, CPBrowsingContext context, const char* url, int width, int height,
406 const char* json_arguments, char** json_retval) {
407 // Should not be called in browser process.
408 return CPERR_FAILURE;
409 }
410
411 CPError STDCALL CPB_ShowHtmlDialog(
412 CPID id, CPBrowsingContext context, const char* url, int width, int height,
413 const char* json_arguments, void* plugin_context) {
414 CHECK(ChromePluginLib::IsPluginThread());
415 ChromePluginLib* plugin = ChromePluginLib::FromCPID(id);
416 CHECK(plugin);
417
418 #if defined(OS_WIN)
419 HWND parent_hwnd = reinterpret_cast<HWND>(static_cast<uintptr_t>(context));
420 PluginService* service = PluginService::GetInstance();
421 if (!service)
422 return CPERR_FAILURE;
423 MessageLoop* main_message_loop = service->main_message_loop();
424 ModelessHtmlDialogDelegate* delegate =
425 new ModelessHtmlDialogDelegate(GURL(url), width, height, json_arguments,
426 plugin_context, plugin, main_message_loop,
427 parent_hwnd);
428 #else
429 // TODO(port): port ModelessHtmlDialogDelegate
430 NOTIMPLEMENTED();
431 #endif
432
433 return CPERR_SUCCESS;
434 }
435
436 CPError STDCALL CPB_GetCommandLineArguments(
437 CPID id, CPBrowsingContext context, const char* url, char** arguments) {
438 CHECK(ChromePluginLib::IsPluginThread());
439 std::string arguments_str;
440 CPError rv = CPB_GetCommandLineArgumentsCommon(url, &arguments_str);
441 if (rv == CPERR_SUCCESS)
442 *arguments = CPB_StringDup(CPB_Alloc, arguments_str);
443 return rv;
444 }
445
446 CPBrowsingContext STDCALL CPB_GetBrowsingContextFromNPP(struct _NPP* npp) {
447 CHECK(ChromePluginLib::IsPluginThread());
448 NOTREACHED() << "NPP does not exist in the browser process.";
449 return 0;
450 }
451
452 int STDCALL CPB_GetBrowsingContextInfo(
453 CPID id, CPBrowsingContext context, CPBrowsingContextInfoType type,
454 void* buf, uint32 buf_size) {
455 CHECK(ChromePluginLib::IsPluginThread());
456 switch (type) {
457 case CPBROWSINGCONTEXT_DATA_DIR_PTR: {
458 if (buf_size < sizeof(char*))
459 return sizeof(char*);
460
461 // TODO(mpcomplete): http://b/1143021 - When we support multiple profiles,
462 // fetch the data dir from the context.
463 PluginService* service = PluginService::GetInstance();
464 if (!service)
465 return CPERR_FAILURE;
466 FilePath path = service->GetChromePluginDataDir();
467 // This is wrong -- we can't in general stuff a path through a std::string.
468 // But this code is Gears-specific, so Windows-only anyway for now.
469 std::string retval;
470 #if defined(OS_WIN)
471 retval = WideToUTF8(path.Append(chrome::kChromePluginDataDirname).value());
472 #else
473 NOTREACHED();
474 #endif
475 *static_cast<char**>(buf) = CPB_StringDup(CPB_Alloc, retval);
476 return CPERR_SUCCESS;
477 }
478 case CPBROWSINGCONTEXT_UI_LOCALE_PTR: {
479 if (buf_size < sizeof(char*))
480 return sizeof(char*);
481
482 PluginService* service = PluginService::GetInstance();
483 if (!service)
484 return CPERR_FAILURE;
485 const std::string& retval = service->GetUILocale();
486 *static_cast<char**>(buf) = CPB_StringDup(CPB_Alloc, retval);
487 return CPERR_SUCCESS;
488 }
489 }
490
491 return CPERR_FAILURE;
492 }
493
494 CPError STDCALL CPB_AddUICommand(CPID id, int command) {
495 CHECK(ChromePluginLib::IsPluginThread());
496 ChromePluginLib* plugin = ChromePluginLib::FromCPID(id);
497 CHECK(plugin);
498
499 PluginCommandHandler::RegisterPlugin(plugin);
500 return CPERR_SUCCESS;
501 }
502
503 static void NotifyGearsShortcutsChanged() {
504 DCHECK(MessageLoop::current() ==
505 PluginService::GetInstance()->main_message_loop());
506
507 // TODO(michaeln): source should be the original profile, fix this
508 // when gears provides the correct browser context, and when we
509 // can relate that to an actual profile.
510 NotificationService::current()->Notify(
511 NotificationType::WEB_APP_INSTALL_CHANGED,
512 Source<Profile>(NULL),
513 NotificationService::NoDetails());
514 }
515
516 CPError STDCALL CPB_HandleCommand(
517 CPID id, CPBrowsingContext context, int command, void *data) {
518 CHECK(ChromePluginLib::IsPluginThread());
519 ChromePluginLib* plugin = ChromePluginLib::FromCPID(id);
520 CHECK(plugin);
521
522 if (command == GEARSBROWSERCOMMAND_CREATE_SHORTCUT_DONE) {
523 GearsCreateShortcutResult* result =
524 static_cast<GearsCreateShortcutResult*>(data);
525 CHECK(result);
526
527 GearsCreateShortcutData* shortcut_data =
528 static_cast<GearsCreateShortcutData*>(result->shortcut);
529 shortcut_data->command_interface->OnCommandResponse(result->result);
530 } else if (command == GEARSBROWSERCOMMAND_NOTIFY_SHORTCUTS_CHANGED) {
531 PluginService* service = PluginService::GetInstance();
532 if (!service)
533 return CPERR_FAILURE;
534 service->main_message_loop()->PostTask(FROM_HERE,
535 NewRunnableFunction(NotifyGearsShortcutsChanged));
536 return CPERR_SUCCESS;
537 }
538 return CPERR_FAILURE;
539 }
540
541 CPError STDCALL CPB_GetDragData(
542 CPID id, CPBrowsingContext context, struct NPObject* event, bool add_data,
543 int32* identity, int32* event_id, char** drag_type, char** drag_data) {
544 *identity = *event_id = 0;
545 NOTREACHED() << "Should not be called in the browser process.";
546 return CPERR_FAILURE;
547 }
548
549 CPError STDCALL CPB_SetDropEffect(
550 CPID id, CPBrowsingContext context, struct NPObject* event, int effect) {
551 NOTREACHED() << "Should not be called in the browser process.";
552 return CPERR_FAILURE;
553 }
554
555 CPError STDCALL CPB_AllowFileDrop(
556 CPID id, CPBrowsingContext context, const char* file_drag_data) {
557 NOTREACHED() << "Should not be called in the browser process.";
558 return CPERR_FAILURE;
559 }
560
561 //
562 // Functions related to network interception
563 //
564
565 void STDCALL CPB_EnableRequestIntercept(CPID id, const char** schemes,
566 uint32 num_schemes) {
567 CHECK(ChromePluginLib::IsPluginThread());
568 ChromePluginLib* plugin = ChromePluginLib::FromCPID(id);
569 CHECK(plugin);
570
571 if (schemes && num_schemes > 0) {
572 PluginRequestInterceptor* interceptor =
573 new PluginRequestInterceptor(plugin);
574 for (uint32 i = 0; i < num_schemes; ++i)
575 interceptor->RegisterProtocol(schemes[i]);
576 } else {
577 PluginRequestInterceptor::DestroyAllHelpersForPlugin(plugin);
578 }
579 }
580
581 void STDCALL CPRR_ReceivedRedirect(CPRequest* request, const char* new_url) {
582 }
583
584 void STDCALL CPRR_StartCompleted(CPRequest* request, CPError result) {
585 CHECK(ChromePluginLib::IsPluginThread());
586 URLRequestInterceptJob* job = URLRequestInterceptJob::FromCPRequest(request);
587 CHECK(job);
588 job->OnStartCompleted(result);
589 }
590
591 void STDCALL CPRR_ReadCompleted(CPRequest* request, int bytes_read) {
592 CHECK(ChromePluginLib::IsPluginThread());
593 URLRequestInterceptJob* job = URLRequestInterceptJob::FromCPRequest(request);
594 CHECK(job);
595 job->OnReadCompleted(bytes_read);
596 }
597
598 void STDCALL CPRR_UploadProgress(CPRequest* request, uint64 pos, uint64 size) {
599 // Does not apply, plugins do not yet intercept uploads
600 }
601
602 //
603 // Functions related to serving network requests to the plugin
604 //
605
606 CPError STDCALL CPB_CreateRequest(CPID id, CPBrowsingContext context,
607 const char* method, const char* url,
608 CPRequest** request) {
609 CHECK(ChromePluginLib::IsPluginThread());
610 ChromePluginLib* plugin = ChromePluginLib::FromCPID(id);
611 CHECK(plugin);
612
613 ScopableCPRequest* cprequest = new ScopableCPRequest(url, method, context);
614 PluginRequestHandler* handler = new PluginRequestHandler(plugin, cprequest);
615 CHECK(handler);
616
617 *request = cprequest;
618 return CPERR_SUCCESS;
619 }
620
621 CPError STDCALL CPR_StartRequest(CPRequest* request) {
622 CHECK(ChromePluginLib::IsPluginThread());
623 PluginRequestHandler* handler = PluginRequestHandler::FromCPRequest(request);
624 CHECK(handler);
625 handler->request()->Start();
626 return CPERR_IO_PENDING;
627 }
628
629 void STDCALL CPR_EndRequest(CPRequest* request, CPError reason) {
630 CHECK(ChromePluginLib::IsPluginThread());
631 PluginRequestHandler* handler = PluginRequestHandler::FromCPRequest(request);
632 delete handler;
633 }
634
635 void STDCALL CPR_SetExtraRequestHeaders(CPRequest* request,
636 const char* headers) {
637 CHECK(ChromePluginLib::IsPluginThread());
638 PluginRequestHandler* handler = PluginRequestHandler::FromCPRequest(request);
639 CHECK(handler);
640 net::HttpRequestHeaders http_headers;
641 http_headers.AddHeadersFromString(headers);
642 handler->request()->SetExtraRequestHeaders(http_headers);
643 }
644
645 void STDCALL CPR_SetRequestLoadFlags(CPRequest* request, uint32 flags) {
646 CHECK(ChromePluginLib::IsPluginThread());
647 PluginRequestHandler* handler = PluginRequestHandler::FromCPRequest(request);
648 CHECK(handler);
649 uint32 net_flags = PluginResponseUtils::CPLoadFlagsToNetFlags(flags);
650 handler->request()->set_load_flags(net_flags);
651 }
652
653 void STDCALL CPR_AppendDataToUpload(CPRequest* request, const char* bytes,
654 int bytes_len) {
655 CHECK(ChromePluginLib::IsPluginThread());
656 PluginRequestHandler* handler = PluginRequestHandler::FromCPRequest(request);
657 CHECK(handler);
658 handler->request()->AppendBytesToUpload(bytes, bytes_len);
659 }
660
661 CPError STDCALL CPR_AppendFileToUpload(CPRequest* request, const char* filepath,
662 uint64 offset, uint64 length) {
663 CHECK(ChromePluginLib::IsPluginThread());
664 PluginRequestHandler* handler = PluginRequestHandler::FromCPRequest(request);
665 CHECK(handler);
666
667 if (!length) length = kuint64max;
668 FilePath path(FilePath::FromWStringHack(UTF8ToWide(filepath)));
669 handler->request()->AppendFileRangeToUpload(path, offset, length,
670 base::Time());
671 return CPERR_SUCCESS;
672 }
673
674 int STDCALL CPR_GetResponseInfo(CPRequest* request, CPResponseInfoType type,
675 void* buf, uint32 buf_size) {
676 CHECK(ChromePluginLib::IsPluginThread());
677 PluginRequestHandler* handler = PluginRequestHandler::FromCPRequest(request);
678 CHECK(handler);
679 return PluginResponseUtils::GetResponseInfo(
680 handler->request()->response_headers(), type, buf, buf_size);
681 }
682
683 int STDCALL CPR_Read(CPRequest* request, void* buf, uint32 buf_size) {
684 CHECK(ChromePluginLib::IsPluginThread());
685 PluginRequestHandler* handler = PluginRequestHandler::FromCPRequest(request);
686 CHECK(handler);
687
688 int bytes_read;
689 if (handler->Read(static_cast<char*>(buf), buf_size, &bytes_read))
690 return bytes_read; // 0 == CPERR_SUCESS
691
692 if (handler->request()->status().is_io_pending())
693 return CPERR_IO_PENDING;
694
695 return CPERR_FAILURE;
696 }
697
698 CPBool STDCALL CPB_IsPluginProcessRunning(CPID id) {
699 CHECK(ChromePluginLib::IsPluginThread());
700 ChromePluginLib* plugin = ChromePluginLib::FromCPID(id);
701 CHECK(plugin);
702 PluginService* service = PluginService::GetInstance();
703 if (!service)
704 return false;
705 PluginProcessHost *host = service->FindNpapiPluginProcess(plugin->filename());
706 return host ? true : false;
707 }
708
709 CPProcessType STDCALL CPB_GetProcessType(CPID id) {
710 CHECK(ChromePluginLib::IsPluginThread());
711 return CP_PROCESS_BROWSER;
712 }
713
714 CPError STDCALL CPB_SendMessage(CPID id, const void *data, uint32 data_len) {
715 CHECK(ChromePluginLib::IsPluginThread());
716 ChromePluginLib* plugin = ChromePluginLib::FromCPID(id);
717 CHECK(plugin);
718
719 PluginService* service = PluginService::GetInstance();
720 if (!service)
721 return CPERR_FAILURE;
722 PluginProcessHost *host =
723 service->FindOrStartNpapiPluginProcess(plugin->filename());
724 if (!host)
725 return CPERR_FAILURE;
726
727 const unsigned char* data_ptr = static_cast<const unsigned char*>(data);
728 std::vector<uint8> v(data_ptr, data_ptr + data_len);
729 #if defined(OS_WIN)
730 if (!host->Send(new PluginProcessMsg_PluginMessage(v)))
731 return CPERR_FAILURE;
732 #else
733 // TODO(port): Implement PluginProcessMsg.
734 NOTIMPLEMENTED();
735 #endif
736
737 return CPERR_SUCCESS;
738 }
739
740 CPError STDCALL CPB_SendSyncMessage(CPID id, const void *data, uint32 data_len,
741 void **retval, uint32 *retval_len) {
742 NOTREACHED() << "Sync messages should not be sent from the browser process.";
743
744 return CPERR_FAILURE;
745 }
746
747 CPError STDCALL CPB_PluginThreadAsyncCall(CPID id,
748 void (*func)(void *),
749 void *user_data) {
750 bool posted = BrowserThread::PostTask(
751 BrowserThread::IO, FROM_HERE,
752 NewRunnableFunction(func, user_data));
753 return posted ? CPERR_SUCCESS : CPERR_FAILURE;
754 }
755
756 CPError STDCALL CPB_OpenFileDialog(CPID id,
757 CPBrowsingContext context,
758 bool multiple_files,
759 const char *title,
760 const char *filter,
761 void *user_data) {
762 NOTREACHED() <<
763 "Open file dialog should only be called from the renderer process.";
764
765 return CPERR_FAILURE;
766 }
767
768 } // namespace
769
770 CPBrowserFuncs* GetCPBrowserFuncsForBrowser() {
771 static CPBrowserFuncs browser_funcs;
772 static CPRequestFuncs request_funcs;
773 static CPResponseFuncs response_funcs;
774 static bool initialized = false;
775 if (!initialized) {
776 initialized = true;
777
778 browser_funcs.size = sizeof(browser_funcs);
779 browser_funcs.version = CP_VERSION;
780 browser_funcs.enable_request_intercept = CPB_EnableRequestIntercept;
781 browser_funcs.create_request = CPB_CreateRequest;
782 browser_funcs.get_cookies = CPB_GetCookies;
783 browser_funcs.alloc = CPB_Alloc;
784 browser_funcs.free = CPB_Free;
785 browser_funcs.set_keep_process_alive = CPB_SetKeepProcessAlive;
786 browser_funcs.show_html_dialog_modal = CPB_ShowHtmlDialogModal;
787 browser_funcs.show_html_dialog = CPB_ShowHtmlDialog;
788 browser_funcs.is_plugin_process_running = CPB_IsPluginProcessRunning;
789 browser_funcs.get_process_type = CPB_GetProcessType;
790 browser_funcs.send_message = CPB_SendMessage;
791 browser_funcs.get_browsing_context_from_npp = CPB_GetBrowsingContextFromNPP;
792 browser_funcs.get_browsing_context_info = CPB_GetBrowsingContextInfo;
793 browser_funcs.get_command_line_arguments = CPB_GetCommandLineArguments;
794 browser_funcs.add_ui_command = CPB_AddUICommand;
795 browser_funcs.handle_command = CPB_HandleCommand;
796
797 browser_funcs.request_funcs = &request_funcs;
798 browser_funcs.response_funcs = &response_funcs;
799 browser_funcs.send_sync_message = CPB_SendSyncMessage;
800 browser_funcs.plugin_thread_async_call = CPB_PluginThreadAsyncCall;
801 browser_funcs.open_file_dialog = CPB_OpenFileDialog;
802 browser_funcs.get_drag_data = CPB_GetDragData;
803 browser_funcs.set_drop_effect = CPB_SetDropEffect;
804 browser_funcs.allow_file_drop = CPB_AllowFileDrop;
805
806 request_funcs.size = sizeof(request_funcs);
807 request_funcs.start_request = CPR_StartRequest;
808 request_funcs.end_request = CPR_EndRequest;
809 request_funcs.set_extra_request_headers = CPR_SetExtraRequestHeaders;
810 request_funcs.set_request_load_flags = CPR_SetRequestLoadFlags;
811 request_funcs.append_data_to_upload = CPR_AppendDataToUpload;
812 request_funcs.get_response_info = CPR_GetResponseInfo;
813 request_funcs.read = CPR_Read;
814 request_funcs.append_file_to_upload = CPR_AppendFileToUpload;
815
816 response_funcs.size = sizeof(response_funcs);
817 response_funcs.received_redirect = CPRR_ReceivedRedirect;
818 response_funcs.start_completed = CPRR_StartCompleted;
819 response_funcs.read_completed = CPRR_ReadCompleted;
820 response_funcs.upload_progress = CPRR_UploadProgress;
821 }
822
823 return &browser_funcs;
824 }
825
826 void CPCommandInterface::OnCommandInvoked(CPError retval) {
827 delete this;
828 }
829
830 void CPCommandInterface::OnCommandResponse(CPError retval) {}
831
832 void CPHandleCommand(int command, CPCommandInterface* data,
833 CPBrowsingContext context) {
834 // Sadly if we try and pass context through, we seem to break cl's little
835 // brain trying to compile the Tuple3 ctor. This cast works.
836 int32 context_as_int32 = static_cast<int32>(context);
837 // Plugins can only be accessed on the IO thread.
838 BrowserThread::PostTask(
839 BrowserThread::IO, FROM_HERE,
840 NewRunnableFunction(PluginCommandHandler::HandleCommand,
841 command, data, context_as_int32));
842 }
OLDNEW
« no previous file with comments | « chrome/browser/chrome_plugin_host.h ('k') | chrome/browser/chrome_plugin_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698