• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/renderer/npapi/webplugin_impl.h"
6 
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/debug/crash_logging.h"
10 #include "base/logging.h"
11 #include "base/memory/linked_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "cc/layers/io_surface_layer.h"
17 #include "content/child/appcache/web_application_cache_host_impl.h"
18 #include "content/child/npapi/plugin_host.h"
19 #include "content/child/npapi/plugin_instance.h"
20 #include "content/child/npapi/webplugin_delegate_impl.h"
21 #include "content/child/npapi/webplugin_resource_client.h"
22 #include "content/common/view_messages.h"
23 #include "content/public/common/content_constants.h"
24 #include "content/public/common/content_switches.h"
25 #include "content/public/renderer/content_renderer_client.h"
26 #include "content/renderer/npapi/webplugin_delegate_proxy.h"
27 #include "content/renderer/render_frame_impl.h"
28 #include "content/renderer/render_process.h"
29 #include "content/renderer/render_thread_impl.h"
30 #include "content/renderer/render_view_impl.h"
31 #include "net/base/escape.h"
32 #include "net/base/net_errors.h"
33 #include "net/http/http_response_headers.h"
34 #include "skia/ext/platform_canvas.h"
35 #include "third_party/WebKit/public/platform/WebCString.h"
36 #include "third_party/WebKit/public/platform/WebCookieJar.h"
37 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
38 #include "third_party/WebKit/public/platform/WebData.h"
39 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
40 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
41 #include "third_party/WebKit/public/platform/WebURL.h"
42 #include "third_party/WebKit/public/platform/WebURLError.h"
43 #include "third_party/WebKit/public/platform/WebURLLoader.h"
44 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
45 #include "third_party/WebKit/public/platform/WebURLResponse.h"
46 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
47 #include "third_party/WebKit/public/web/WebDocument.h"
48 #include "third_party/WebKit/public/web/WebFrame.h"
49 #include "third_party/WebKit/public/web/WebInputEvent.h"
50 #include "third_party/WebKit/public/web/WebKit.h"
51 #include "third_party/WebKit/public/web/WebPluginContainer.h"
52 #include "third_party/WebKit/public/web/WebPluginParams.h"
53 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
54 #include "third_party/WebKit/public/web/WebView.h"
55 #include "ui/gfx/rect.h"
56 #include "url/gurl.h"
57 #include "url/url_util.h"
58 #include "webkit/child/multipart_response_delegate.h"
59 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
60 
61 using blink::WebCanvas;
62 using blink::WebConsoleMessage;
63 using blink::WebCookieJar;
64 using blink::WebCString;
65 using blink::WebCursorInfo;
66 using blink::WebData;
67 using blink::WebDataSource;
68 using blink::WebFrame;
69 using blink::WebHTTPBody;
70 using blink::WebHTTPHeaderVisitor;
71 using blink::WebInputEvent;
72 using blink::WebKeyboardEvent;
73 using blink::WebMouseEvent;
74 using blink::WebPluginContainer;
75 using blink::WebPluginParams;
76 using blink::WebRect;
77 using blink::WebString;
78 using blink::WebURL;
79 using blink::WebURLError;
80 using blink::WebURLLoader;
81 using blink::WebURLLoaderClient;
82 using blink::WebURLLoaderOptions;
83 using blink::WebURLRequest;
84 using blink::WebURLResponse;
85 using blink::WebVector;
86 using blink::WebView;
87 using webkit_glue::MultipartResponseDelegate;
88 
89 namespace content {
90 
91 namespace {
92 
93 // This class handles individual multipart responses. It is instantiated when
94 // we receive HTTP status code 206 in the HTTP response. This indicates
95 // that the response could have multiple parts each separated by a boundary
96 // specified in the response header.
97 class MultiPartResponseClient : public WebURLLoaderClient {
98  public:
MultiPartResponseClient(WebPluginResourceClient * resource_client)99   explicit MultiPartResponseClient(WebPluginResourceClient* resource_client)
100       : byte_range_lower_bound_(0), resource_client_(resource_client) {}
101 
willSendRequest(WebURLLoader *,WebURLRequest &,const WebURLResponse &)102   virtual void willSendRequest(
103       WebURLLoader*, WebURLRequest&, const WebURLResponse&) {}
didSendData(WebURLLoader *,unsigned long long,unsigned long long)104   virtual void didSendData(
105       WebURLLoader*, unsigned long long, unsigned long long) {}
106 
107   // Called when the multipart parser encounters an embedded multipart
108   // response.
didReceiveResponse(WebURLLoader *,const WebURLResponse & response)109   virtual void didReceiveResponse(
110       WebURLLoader*, const WebURLResponse& response) {
111     int64 byte_range_upper_bound, instance_size;
112     if (!MultipartResponseDelegate::ReadContentRanges(
113             response,
114             &byte_range_lower_bound_,
115             &byte_range_upper_bound,
116             &instance_size)) {
117       NOTREACHED();
118     }
119   }
120 
121   // Receives individual part data from a multipart response.
didReceiveData(WebURLLoader *,const char * data,int data_length,int encoded_data_length)122   virtual void didReceiveData(WebURLLoader*,
123                               const char* data,
124                               int data_length,
125                               int encoded_data_length) {
126     // TODO(ananta)
127     // We should defer further loads on multipart resources on the same lines
128     // as regular resources requested by plugins to prevent reentrancy.
129     resource_client_->DidReceiveData(
130         data, data_length, byte_range_lower_bound_);
131     byte_range_lower_bound_ += data_length;
132   }
133 
didFinishLoading(WebURLLoader *,double finishTime)134   virtual void didFinishLoading(WebURLLoader*, double finishTime) {}
didFail(WebURLLoader *,const WebURLError &)135   virtual void didFail(WebURLLoader*, const WebURLError&) {}
136 
137  private:
138   // The lower bound of the byte range.
139   int64 byte_range_lower_bound_;
140   // The handler for the data.
141   WebPluginResourceClient* resource_client_;
142 };
143 
144 class HeaderFlattener : public WebHTTPHeaderVisitor {
145  public:
HeaderFlattener(std::string * buf)146   explicit HeaderFlattener(std::string* buf) : buf_(buf) {
147   }
148 
visitHeader(const WebString & name,const WebString & value)149   virtual void visitHeader(const WebString& name, const WebString& value) {
150     // TODO(darin): Should we really exclude headers with an empty value?
151     if (!name.isEmpty() && !value.isEmpty()) {
152       buf_->append(name.utf8());
153       buf_->append(": ");
154       buf_->append(value.utf8());
155       buf_->append("\n");
156     }
157   }
158 
159  private:
160   std::string* buf_;
161 };
162 
GetAllHeaders(const WebURLResponse & response)163 std::string GetAllHeaders(const WebURLResponse& response) {
164   // TODO(darin): It is possible for httpStatusText to be empty and still have
165   // an interesting response, so this check seems wrong.
166   std::string result;
167   const WebString& status = response.httpStatusText();
168   if (status.isEmpty())
169     return result;
170 
171   // TODO(darin): Shouldn't we also report HTTP version numbers?
172   result = base::StringPrintf("HTTP %d ", response.httpStatusCode());
173   result.append(status.utf8());
174   result.append("\n");
175 
176   HeaderFlattener flattener(&result);
177   response.visitHTTPHeaderFields(&flattener);
178 
179   return result;
180 }
181 
182 struct ResponseInfo {
183   GURL url;
184   std::string mime_type;
185   uint32 last_modified;
186   uint32 expected_length;
187 };
188 
GetResponseInfo(const WebURLResponse & response,ResponseInfo * response_info)189 void GetResponseInfo(const WebURLResponse& response,
190                      ResponseInfo* response_info) {
191   response_info->url = response.url();
192   response_info->mime_type = response.mimeType().utf8();
193 
194   // Measured in seconds since 12:00 midnight GMT, January 1, 1970.
195   response_info->last_modified =
196       static_cast<uint32>(response.lastModifiedDate());
197 
198   // If the length comes in as -1, then it indicates that it was not
199   // read off the HTTP headers. We replicate Safari webkit behavior here,
200   // which is to set it to 0.
201   response_info->expected_length =
202       static_cast<uint32>(std::max(response.expectedContentLength(), 0LL));
203 
204   WebString content_encoding =
205       response.httpHeaderField(WebString::fromUTF8("Content-Encoding"));
206   if (!content_encoding.isNull() &&
207       !EqualsASCII(content_encoding, "identity")) {
208     // Don't send the compressed content length to the plugin, which only
209     // cares about the decoded length.
210     response_info->expected_length = 0;
211   }
212 }
213 
214 }  // namespace
215 
216 // blink::WebPlugin ----------------------------------------------------------
217 
218 struct WebPluginImpl::ClientInfo {
219   unsigned long id;
220   WebPluginResourceClient* client;
221   blink::WebURLRequest request;
222   bool pending_failure_notification;
223   linked_ptr<blink::WebURLLoader> loader;
224   bool notify_redirects;
225   bool is_plugin_src_load;
226   int64 data_offset;
227 };
228 
initialize(WebPluginContainer * container)229 bool WebPluginImpl::initialize(WebPluginContainer* container) {
230   if (!render_view_.get()) {
231     LOG(ERROR) << "No RenderView";
232     return false;
233   }
234 
235   WebPluginDelegate* plugin_delegate = CreatePluginDelegate();
236   if (!plugin_delegate)
237     return false;
238 
239   // Store the plugin's unique identifier, used by the container to track its
240   // script objects.
241   npp_ = plugin_delegate->GetPluginNPP();
242 
243   // Set the container before Initialize because the plugin may
244   // synchronously call NPN_GetValue to get its container, or make calls
245   // passing script objects that need to be tracked, during initialization.
246   SetContainer(container);
247 
248   bool ok = plugin_delegate->Initialize(
249       plugin_url_, arg_names_, arg_values_, load_manually_);
250   if (!ok) {
251     plugin_delegate->PluginDestroyed();
252 
253     blink::WebPlugin* replacement_plugin =
254         GetContentClient()->renderer()->CreatePluginReplacement(
255             render_frame_, file_path_);
256     if (!replacement_plugin)
257       return false;
258 
259     // Disable scripting by this plugin before replacing it with the new
260     // one. This plugin also needs destroying, so use destroy(), which will
261     // implicitly disable scripting while un-setting the container.
262     destroy();
263 
264     // Inform the container of the replacement plugin, then initialize it.
265     container->setPlugin(replacement_plugin);
266     return replacement_plugin->initialize(container);
267   }
268 
269   delegate_ = plugin_delegate;
270 
271   return true;
272 }
273 
destroy()274 void WebPluginImpl::destroy() {
275   SetContainer(NULL);
276   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
277 }
278 
scriptableObject()279 NPObject* WebPluginImpl::scriptableObject() {
280   if (!delegate_)
281     return NULL;
282 
283   return delegate_->GetPluginScriptableObject();
284 }
285 
pluginNPP()286 NPP WebPluginImpl::pluginNPP() {
287   return npp_;
288 }
289 
getFormValue(blink::WebString & value)290 bool WebPluginImpl::getFormValue(blink::WebString& value) {
291   if (!delegate_)
292     return false;
293   base::string16 form_value;
294   if (!delegate_->GetFormValue(&form_value))
295     return false;
296   value = form_value;
297   return true;
298 }
299 
paint(WebCanvas * canvas,const WebRect & paint_rect)300 void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) {
301   if (!delegate_ || !container_)
302     return;
303 
304 #if defined(OS_WIN)
305   // Force a geometry update if needed to allow plugins like media player
306   // which defer the initial geometry update to work.
307   container_->reportGeometry();
308 #endif  // OS_WIN
309 
310   // Note that |canvas| is only used when in windowless mode.
311   delegate_->Paint(canvas, paint_rect);
312 }
313 
updateGeometry(const WebRect & window_rect,const WebRect & clip_rect,const WebVector<WebRect> & cutout_rects,bool is_visible)314 void WebPluginImpl::updateGeometry(
315     const WebRect& window_rect, const WebRect& clip_rect,
316     const WebVector<WebRect>& cutout_rects, bool is_visible) {
317   WebPluginGeometry new_geometry;
318   new_geometry.window = window_;
319   new_geometry.window_rect = window_rect;
320   new_geometry.clip_rect = clip_rect;
321   new_geometry.visible = is_visible;
322   new_geometry.rects_valid = true;
323   for (size_t i = 0; i < cutout_rects.size(); ++i)
324     new_geometry.cutout_rects.push_back(cutout_rects[i]);
325 
326   // Only send DidMovePlugin if the geometry changed in some way.
327   if (window_ && render_view_.get() &&
328       (first_geometry_update_ || !new_geometry.Equals(geometry_))) {
329     render_view_->SchedulePluginMove(new_geometry);
330     // We invalidate windowed plugins during the first geometry update to
331     // ensure that they get reparented to the wrapper window in the browser.
332     // This ensures that they become visible and are painted by the OS. This is
333     // required as some pages don't invalidate when the plugin is added.
334     if (first_geometry_update_ && window_) {
335       InvalidateRect(window_rect);
336     }
337   }
338 
339   // Only UpdateGeometry if either the window or clip rects have changed.
340   if (delegate_ && (first_geometry_update_ ||
341       new_geometry.window_rect != geometry_.window_rect ||
342       new_geometry.clip_rect != geometry_.clip_rect)) {
343     // Notify the plugin that its parameters have changed.
344     delegate_->UpdateGeometry(new_geometry.window_rect, new_geometry.clip_rect);
345   }
346 
347   // Initiate a download on the plugin url. This should be done for the
348   // first update geometry sequence. We need to ensure that the plugin
349   // receives the geometry update before it starts receiving data.
350   if (first_geometry_update_) {
351     // An empty url corresponds to an EMBED tag with no src attribute.
352     if (!load_manually_ && plugin_url_.is_valid()) {
353       // The Flash plugin hangs for a while if it receives data before
354       // receiving valid plugin geometry. By valid geometry we mean the
355       // geometry received by a call to setFrameRect in the Webkit
356       // layout code path. To workaround this issue we download the
357       // plugin source url on a timer.
358       base::MessageLoop::current()->PostTask(
359           FROM_HERE,
360           base::Bind(&WebPluginImpl::OnDownloadPluginSrcUrl,
361                      weak_factory_.GetWeakPtr()));
362     }
363   }
364 
365 #if defined(OS_WIN)
366   // Don't cache the geometry during the first geometry update. The first
367   // geometry update sequence is received when Widget::setParent is called.
368   // For plugins like media player which have a bug where they only honor
369   // the first geometry update, we have a quirk which ignores the first
370   // geometry update. To ensure that these plugins work correctly in cases
371   // where we receive only one geometry update from webkit, we also force
372   // a geometry update during paint which should go out correctly as the
373   // initial geometry update was not cached.
374   if (!first_geometry_update_)
375     geometry_ = new_geometry;
376 #else  // OS_WIN
377   geometry_ = new_geometry;
378 #endif  // OS_WIN
379   first_geometry_update_ = false;
380 }
381 
updateFocus(bool focused)382 void WebPluginImpl::updateFocus(bool focused) {
383   if (accepts_input_events_)
384     delegate_->SetFocus(focused);
385 }
386 
updateVisibility(bool visible)387 void WebPluginImpl::updateVisibility(bool visible) {
388   if (!window_ || !render_view_.get())
389     return;
390 
391   WebPluginGeometry move;
392   move.window = window_;
393   move.window_rect = gfx::Rect();
394   move.clip_rect = gfx::Rect();
395   move.rects_valid = false;
396   move.visible = visible;
397 
398   render_view_->SchedulePluginMove(move);
399 }
400 
acceptsInputEvents()401 bool WebPluginImpl::acceptsInputEvents() {
402   return accepts_input_events_;
403 }
404 
handleInputEvent(const WebInputEvent & event,WebCursorInfo & cursor_info)405 bool WebPluginImpl::handleInputEvent(
406     const WebInputEvent& event, WebCursorInfo& cursor_info) {
407   // Swallow context menu events in order to suppress the default context menu.
408   if (event.type == WebInputEvent::ContextMenu)
409     return true;
410 
411   WebCursor::CursorInfo web_cursor_info;
412   bool ret = delegate_->HandleInputEvent(event, &web_cursor_info);
413   cursor_info.type = web_cursor_info.type;
414   cursor_info.hotSpot = web_cursor_info.hotspot;
415   cursor_info.customImage = web_cursor_info.custom_image;
416   cursor_info.imageScaleFactor = web_cursor_info.image_scale_factor;
417 #if defined(OS_WIN)
418   cursor_info.externalHandle = web_cursor_info.external_handle;
419 #endif
420   return ret;
421 }
422 
didReceiveResponse(const WebURLResponse & response)423 void WebPluginImpl::didReceiveResponse(const WebURLResponse& response) {
424   ignore_response_error_ = false;
425 
426   ResponseInfo response_info;
427   GetResponseInfo(response, &response_info);
428 
429   delegate_->DidReceiveManualResponse(
430       response_info.url,
431       response_info.mime_type,
432       GetAllHeaders(response),
433       response_info.expected_length,
434       response_info.last_modified);
435 }
436 
didReceiveData(const char * data,int data_length)437 void WebPluginImpl::didReceiveData(const char* data, int data_length) {
438   delegate_->DidReceiveManualData(data, data_length);
439 }
440 
didFinishLoading()441 void WebPluginImpl::didFinishLoading() {
442   delegate_->DidFinishManualLoading();
443 }
444 
didFailLoading(const WebURLError & error)445 void WebPluginImpl::didFailLoading(const WebURLError& error) {
446   if (!ignore_response_error_)
447     delegate_->DidManualLoadFail();
448 }
449 
didFinishLoadingFrameRequest(const WebURL & url,void * notify_data)450 void WebPluginImpl::didFinishLoadingFrameRequest(
451     const WebURL& url, void* notify_data) {
452   if (delegate_) {
453     // We're converting a void* into an arbitrary int id.  Though
454     // these types are the same size on all the platforms we support,
455     // the compiler may complain as though they are different, so to
456     // make the casting gods happy go through an intptr_t (the union
457     // of void* and int) rather than converting straight across.
458     delegate_->DidFinishLoadWithReason(
459         url, NPRES_DONE, reinterpret_cast<intptr_t>(notify_data));
460   }
461 }
462 
didFailLoadingFrameRequest(const WebURL & url,void * notify_data,const WebURLError & error)463 void WebPluginImpl::didFailLoadingFrameRequest(
464     const WebURL& url, void* notify_data, const WebURLError& error) {
465   if (!delegate_)
466     return;
467 
468   NPReason reason =
469       error.reason == net::ERR_ABORTED ? NPRES_USER_BREAK : NPRES_NETWORK_ERR;
470   // See comment in didFinishLoadingFrameRequest about the cast here.
471   delegate_->DidFinishLoadWithReason(
472       url, reason, reinterpret_cast<intptr_t>(notify_data));
473 }
474 
isPlaceholder()475 bool WebPluginImpl::isPlaceholder() {
476   return false;
477 }
478 
479 // -----------------------------------------------------------------------------
480 
WebPluginImpl(WebFrame * webframe,const WebPluginParams & params,const base::FilePath & file_path,const base::WeakPtr<RenderViewImpl> & render_view,RenderFrameImpl * render_frame)481 WebPluginImpl::WebPluginImpl(
482     WebFrame* webframe,
483     const WebPluginParams& params,
484     const base::FilePath& file_path,
485     const base::WeakPtr<RenderViewImpl>& render_view,
486     RenderFrameImpl* render_frame)
487     : windowless_(false),
488       window_(gfx::kNullPluginWindow),
489       accepts_input_events_(false),
490       render_frame_(render_frame),
491       render_view_(render_view),
492       webframe_(webframe),
493       delegate_(NULL),
494       container_(NULL),
495       npp_(NULL),
496       plugin_url_(params.url),
497       load_manually_(params.loadManually),
498       first_geometry_update_(true),
499       ignore_response_error_(false),
500       file_path_(file_path),
501       mime_type_(UTF16ToASCII(params.mimeType)),
502       weak_factory_(this) {
503   DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size());
504   StringToLowerASCII(&mime_type_);
505 
506   for (size_t i = 0; i < params.attributeNames.size(); ++i) {
507     arg_names_.push_back(params.attributeNames[i].utf8());
508     arg_values_.push_back(params.attributeValues[i].utf8());
509   }
510 
511   // Set subresource URL for crash reporting.
512   base::debug::SetCrashKeyValue("subresource_url", plugin_url_.spec());
513 }
514 
~WebPluginImpl()515 WebPluginImpl::~WebPluginImpl() {
516 }
517 
SetWindow(gfx::PluginWindowHandle window)518 void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window) {
519   if (window) {
520     DCHECK(!windowless_);
521     window_ = window;
522 #if defined(OS_MACOSX)
523     // TODO(kbr): remove. http://crbug.com/105344
524 
525     // Lie to ourselves about being windowless even if we got a fake
526     // plugin window handle, so we continue to get input events.
527     windowless_ = true;
528     accepts_input_events_ = true;
529     // We do not really need to notify the page delegate that a plugin
530     // window was created -- so don't.
531 #else
532     accepts_input_events_ = false;
533 
534 #if defined(USE_X11)
535     // Tell the view delegate that the plugin window was created, so that it
536     // can create necessary container widgets.
537     render_view_->Send(new ViewHostMsg_CreatePluginContainer(
538         render_view_->routing_id(), window));
539 #endif  // USE_X11
540 
541 #endif  // OS_MACOSX
542   } else {
543     DCHECK(!window_);  // Make sure not called twice.
544     windowless_ = true;
545     accepts_input_events_ = true;
546   }
547 }
548 
SetAcceptsInputEvents(bool accepts)549 void WebPluginImpl::SetAcceptsInputEvents(bool accepts) {
550   accepts_input_events_ = accepts;
551 }
552 
WillDestroyWindow(gfx::PluginWindowHandle window)553 void WebPluginImpl::WillDestroyWindow(gfx::PluginWindowHandle window) {
554   DCHECK_EQ(window, window_);
555   window_ = gfx::kNullPluginWindow;
556   if (render_view_.get()) {
557 #if defined(USE_X11)
558     render_view_->Send(new ViewHostMsg_DestroyPluginContainer(
559         render_view_->routing_id(), window));
560 #endif
561     render_view_->CleanupWindowInPluginMoves(window);
562   }
563 }
564 
CompleteURL(const char * url)565 GURL WebPluginImpl::CompleteURL(const char* url) {
566   if (!webframe_) {
567     NOTREACHED();
568     return GURL();
569   }
570   // TODO(darin): Is conversion from UTF8 correct here?
571   return webframe_->document().completeURL(WebString::fromUTF8(url));
572 }
573 
CancelResource(unsigned long id)574 void WebPluginImpl::CancelResource(unsigned long id) {
575   for (size_t i = 0; i < clients_.size(); ++i) {
576     if (clients_[i].id == id) {
577       if (clients_[i].loader.get()) {
578         clients_[i].loader->setDefersLoading(false);
579         clients_[i].loader->cancel();
580         RemoveClient(i);
581       }
582       return;
583     }
584   }
585 }
586 
SetPostData(WebURLRequest * request,const char * buf,uint32 length)587 bool WebPluginImpl::SetPostData(WebURLRequest* request,
588                                 const char *buf,
589                                 uint32 length) {
590   std::vector<std::string> names;
591   std::vector<std::string> values;
592   std::vector<char> body;
593   bool rv = PluginHost::SetPostData(buf, length, &names, &values, &body);
594 
595   for (size_t i = 0; i < names.size(); ++i) {
596     request->addHTTPHeaderField(WebString::fromUTF8(names[i]),
597                                 WebString::fromUTF8(values[i]));
598   }
599 
600   WebString content_type_header = WebString::fromUTF8("Content-Type");
601   const WebString& content_type =
602       request->httpHeaderField(content_type_header);
603   if (content_type.isEmpty()) {
604     request->setHTTPHeaderField(
605         content_type_header,
606         WebString::fromUTF8("application/x-www-form-urlencoded"));
607   }
608 
609   WebHTTPBody http_body;
610   if (body.size()) {
611     http_body.initialize();
612     http_body.appendData(WebData(&body[0], body.size()));
613   }
614   request->setHTTPBody(http_body);
615 
616   return rv;
617 }
618 
IsValidUrl(const GURL & url,Referrer referrer_flag)619 bool WebPluginImpl::IsValidUrl(const GURL& url, Referrer referrer_flag) {
620   if (referrer_flag == PLUGIN_SRC &&
621       mime_type_ == kFlashPluginSwfMimeType &&
622       url.GetOrigin() != plugin_url_.GetOrigin()) {
623     // Do url check to make sure that there are no @, ;, \ chars in between url
624     // scheme and url path.
625     const char* url_to_check(url.spec().data());
626     url_parse::Parsed parsed;
627     url_parse::ParseStandardURL(url_to_check, strlen(url_to_check), &parsed);
628     if (parsed.path.begin <= parsed.scheme.end())
629       return true;
630     std::string string_to_search;
631     string_to_search.assign(url_to_check + parsed.scheme.end(),
632         parsed.path.begin - parsed.scheme.end());
633     if (string_to_search.find("@") != std::string::npos ||
634         string_to_search.find(";") != std::string::npos ||
635         string_to_search.find("\\") != std::string::npos)
636       return false;
637   }
638 
639   return true;
640 }
641 
CreatePluginDelegate()642 WebPluginDelegate* WebPluginImpl::CreatePluginDelegate() {
643   bool in_process_plugin = RenderProcess::current()->UseInProcessPlugins();
644   if (in_process_plugin) {
645 #if defined(OS_WIN) && !defined(USE_AURA)
646     return WebPluginDelegateImpl::Create(this, file_path_, mime_type_);
647 #else
648     // In-proc plugins aren't supported on non-Windows.
649     NOTIMPLEMENTED();
650     return NULL;
651 #endif
652   }
653 
654   return new WebPluginDelegateProxy(
655       this, mime_type_, render_view_, render_frame_);
656 }
657 
RouteToFrame(const char * url,bool is_javascript_url,bool popups_allowed,const char * method,const char * target,const char * buf,unsigned int len,int notify_id,Referrer referrer_flag)658 WebPluginImpl::RoutingStatus WebPluginImpl::RouteToFrame(
659     const char* url,
660     bool is_javascript_url,
661     bool popups_allowed,
662     const char* method,
663     const char* target,
664     const char* buf,
665     unsigned int len,
666     int notify_id,
667     Referrer referrer_flag) {
668   // If there is no target, there is nothing to do
669   if (!target)
670     return NOT_ROUTED;
671 
672   // This could happen if the WebPluginContainer was already deleted.
673   if (!webframe_)
674     return NOT_ROUTED;
675 
676   WebString target_str = WebString::fromUTF8(target);
677 
678   // Take special action for JavaScript URLs
679   if (is_javascript_url) {
680     WebFrame* target_frame =
681         webframe_->view()->findFrameByName(target_str, webframe_);
682     // For security reasons, do not allow JavaScript on frames
683     // other than this frame.
684     if (target_frame != webframe_) {
685       // TODO(darin): Localize this message.
686       const char kMessage[] =
687           "Ignoring cross-frame javascript URL load requested by plugin.";
688       webframe_->addMessageToConsole(
689           WebConsoleMessage(WebConsoleMessage::LevelError,
690                             WebString::fromUTF8(kMessage)));
691       return ROUTED;
692     }
693 
694     // Route javascript calls back to the plugin.
695     return NOT_ROUTED;
696   }
697 
698   // If we got this far, we're routing content to a target frame.
699   // Go fetch the URL.
700 
701   GURL complete_url = CompleteURL(url);
702   // Remove when flash bug is fixed. http://crbug.com/40016.
703   if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
704     return INVALID_URL;
705 
706   if (strcmp(method, "GET") != 0) {
707     // We're only going to route HTTP/HTTPS requests
708     if (!complete_url.SchemeIsHTTPOrHTTPS())
709       return INVALID_URL;
710   }
711 
712   WebURLRequest request(complete_url);
713   SetReferrer(&request, referrer_flag);
714 
715   request.setHTTPMethod(WebString::fromUTF8(method));
716   request.setFirstPartyForCookies(
717       webframe_->document().firstPartyForCookies());
718   request.setHasUserGesture(popups_allowed);
719   if (len > 0) {
720     if (!SetPostData(&request, buf, len)) {
721       // Uhoh - we're in trouble.  There isn't a good way
722       // to recover at this point.  Break out.
723       NOTREACHED();
724       return ROUTED;
725     }
726   }
727 
728   container_->loadFrameRequest(
729       request, target_str, notify_id != 0, reinterpret_cast<void*>(notify_id));
730   return ROUTED;
731 }
732 
GetWindowScriptNPObject()733 NPObject* WebPluginImpl::GetWindowScriptNPObject() {
734   if (!webframe_) {
735     NOTREACHED();
736     return NULL;
737   }
738   return webframe_->windowObject();
739 }
740 
GetPluginElement()741 NPObject* WebPluginImpl::GetPluginElement() {
742   return container_->scriptableObjectForElement();
743 }
744 
FindProxyForUrl(const GURL & url,std::string * proxy_list)745 bool WebPluginImpl::FindProxyForUrl(const GURL& url, std::string* proxy_list) {
746   // Proxy resolving doesn't work in single-process mode.
747   return false;
748 }
749 
SetCookie(const GURL & url,const GURL & first_party_for_cookies,const std::string & cookie)750 void WebPluginImpl::SetCookie(const GURL& url,
751                               const GURL& first_party_for_cookies,
752                               const std::string& cookie) {
753   if (!render_view_.get())
754     return;
755 
756   WebCookieJar* cookie_jar = render_view_->cookie_jar();
757   if (!cookie_jar) {
758     DLOG(WARNING) << "No cookie jar!";
759     return;
760   }
761 
762   cookie_jar->setCookie(
763       url, first_party_for_cookies, WebString::fromUTF8(cookie));
764 }
765 
GetCookies(const GURL & url,const GURL & first_party_for_cookies)766 std::string WebPluginImpl::GetCookies(const GURL& url,
767                                       const GURL& first_party_for_cookies) {
768   if (!render_view_.get())
769     return std::string();
770 
771   WebCookieJar* cookie_jar = render_view_->cookie_jar();
772   if (!cookie_jar) {
773     DLOG(WARNING) << "No cookie jar!";
774     return std::string();
775   }
776 
777   return UTF16ToUTF8(cookie_jar->cookies(url, first_party_for_cookies));
778 }
779 
URLRedirectResponse(bool allow,int resource_id)780 void WebPluginImpl::URLRedirectResponse(bool allow, int resource_id) {
781   for (size_t i = 0; i < clients_.size(); ++i) {
782     if (clients_[i].id == static_cast<unsigned long>(resource_id)) {
783       if (clients_[i].loader.get()) {
784         if (allow) {
785           clients_[i].loader->setDefersLoading(false);
786         } else {
787           clients_[i].loader->cancel();
788           if (clients_[i].client)
789             clients_[i].client->DidFail(clients_[i].id);
790         }
791       }
792       break;
793     }
794   }
795 }
796 
CheckIfRunInsecureContent(const GURL & url)797 bool WebPluginImpl::CheckIfRunInsecureContent(const GURL& url) {
798   if (!webframe_)
799     return true;
800 
801   return webframe_->checkIfRunInsecureContent(url);
802 }
803 
804 #if defined(OS_MACOSX)
GetAcceleratedSurface(gfx::GpuPreference gpu_preference)805 WebPluginAcceleratedSurface* WebPluginImpl::GetAcceleratedSurface(
806     gfx::GpuPreference gpu_preference) {
807   return NULL;
808 }
809 
AcceleratedPluginEnabledRendering()810 void WebPluginImpl::AcceleratedPluginEnabledRendering() {
811 }
812 
AcceleratedPluginAllocatedIOSurface(int32 width,int32 height,uint32 surface_id)813 void WebPluginImpl::AcceleratedPluginAllocatedIOSurface(int32 width,
814                                                         int32 height,
815                                                         uint32 surface_id) {
816   next_io_surface_allocated_ = true;
817   next_io_surface_width_ = width;
818   next_io_surface_height_ = height;
819   next_io_surface_id_ = surface_id;
820 }
821 
AcceleratedPluginSwappedIOSurface()822 void WebPluginImpl::AcceleratedPluginSwappedIOSurface() {
823   if (!container_)
824     return;
825   // Deferring the call to setBackingIOSurfaceId is an attempt to
826   // work around garbage occasionally showing up in the plugin's
827   // area during live resizing of Core Animation plugins. The
828   // assumption was that by the time this was called, the plugin
829   // process would have populated the newly allocated IOSurface. It
830   // is not 100% clear at this point why any garbage is getting
831   // through. More investigation is needed. http://crbug.com/105346
832   if (next_io_surface_allocated_) {
833     if (next_io_surface_id_) {
834       if (!io_surface_layer_.get()) {
835         io_surface_layer_ = cc::IOSurfaceLayer::Create();
836         web_layer_.reset(new webkit::WebLayerImpl(io_surface_layer_));
837         container_->setWebLayer(web_layer_.get());
838       }
839       io_surface_layer_->SetIOSurfaceProperties(
840           next_io_surface_id_,
841           gfx::Size(next_io_surface_width_, next_io_surface_height_));
842     } else {
843       container_->setWebLayer(NULL);
844       web_layer_.reset();
845       io_surface_layer_ = NULL;
846     }
847     next_io_surface_allocated_ = false;
848   } else {
849     if (io_surface_layer_.get())
850       io_surface_layer_->SetNeedsDisplay();
851   }
852 }
853 #endif
854 
Invalidate()855 void WebPluginImpl::Invalidate() {
856   if (container_)
857     container_->invalidate();
858 }
859 
InvalidateRect(const gfx::Rect & rect)860 void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) {
861   if (container_)
862     container_->invalidateRect(rect);
863 }
864 
OnDownloadPluginSrcUrl()865 void WebPluginImpl::OnDownloadPluginSrcUrl() {
866   HandleURLRequestInternal(
867       plugin_url_.spec().c_str(), "GET", NULL, NULL, 0, 0, false, DOCUMENT_URL,
868       false, true);
869 }
870 
GetClientFromLoader(WebURLLoader * loader)871 WebPluginResourceClient* WebPluginImpl::GetClientFromLoader(
872     WebURLLoader* loader) {
873   ClientInfo* client_info = GetClientInfoFromLoader(loader);
874   if (client_info)
875     return client_info->client;
876   return NULL;
877 }
878 
GetClientInfoFromLoader(WebURLLoader * loader)879 WebPluginImpl::ClientInfo* WebPluginImpl::GetClientInfoFromLoader(
880     WebURLLoader* loader) {
881   for (size_t i = 0; i < clients_.size(); ++i) {
882     if (clients_[i].loader.get() == loader)
883       return &clients_[i];
884   }
885 
886   NOTREACHED();
887   return 0;
888 }
889 
willSendRequest(WebURLLoader * loader,WebURLRequest & request,const WebURLResponse & response)890 void WebPluginImpl::willSendRequest(WebURLLoader* loader,
891                                     WebURLRequest& request,
892                                     const WebURLResponse& response) {
893   // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedRedirect
894   // until kDirectNPAPIRequests is the default and we can remove this old path.
895   WebPluginImpl::ClientInfo* client_info = GetClientInfoFromLoader(loader);
896   if (client_info) {
897     // Currently this check is just to catch an https -> http redirect when
898     // loading the main plugin src URL. Longer term, we could investigate
899     // firing mixed diplay or scripting issues for subresource loads
900     // initiated by plug-ins.
901     if (client_info->is_plugin_src_load &&
902         webframe_ &&
903         !webframe_->checkIfRunInsecureContent(request.url())) {
904       loader->cancel();
905       client_info->client->DidFail(client_info->id);
906       return;
907     }
908     if (net::HttpResponseHeaders::IsRedirectResponseCode(
909             response.httpStatusCode())) {
910       // If the plugin does not participate in url redirect notifications then
911       // just block cross origin 307 POST redirects.
912       if (!client_info->notify_redirects) {
913         if (response.httpStatusCode() == 307 &&
914             LowerCaseEqualsASCII(request.httpMethod().utf8(), "post")) {
915           GURL original_request_url(response.url());
916           GURL response_url(request.url());
917           if (original_request_url.GetOrigin() != response_url.GetOrigin()) {
918             loader->setDefersLoading(true);
919             loader->cancel();
920             client_info->client->DidFail(client_info->id);
921             return;
922           }
923         }
924       } else {
925         loader->setDefersLoading(true);
926       }
927     }
928     client_info->client->WillSendRequest(request.url(),
929                                          response.httpStatusCode());
930   }
931 }
932 
didSendData(WebURLLoader * loader,unsigned long long bytes_sent,unsigned long long total_bytes_to_be_sent)933 void WebPluginImpl::didSendData(WebURLLoader* loader,
934                                 unsigned long long bytes_sent,
935                                 unsigned long long total_bytes_to_be_sent) {
936 }
937 
didReceiveResponse(WebURLLoader * loader,const WebURLResponse & response)938 void WebPluginImpl::didReceiveResponse(WebURLLoader* loader,
939                                        const WebURLResponse& response) {
940   // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedResponse
941   // until kDirectNPAPIRequests is the default and we can remove this old path.
942   static const int kHttpPartialResponseStatusCode = 206;
943   static const int kHttpResponseSuccessStatusCode = 200;
944 
945   WebPluginResourceClient* client = GetClientFromLoader(loader);
946   if (!client)
947     return;
948 
949   ResponseInfo response_info;
950   GetResponseInfo(response, &response_info);
951   ClientInfo* client_info = GetClientInfoFromLoader(loader);
952   if (!client_info)
953     return;
954 
955   bool request_is_seekable = true;
956   if (client->IsMultiByteResponseExpected()) {
957     if (response.httpStatusCode() == kHttpPartialResponseStatusCode) {
958       ClientInfo* client_info = GetClientInfoFromLoader(loader);
959       if (!client_info)
960         return;
961       if (HandleHttpMultipartResponse(response, client)) {
962         // Multiple ranges requested, data will be delivered by
963         // MultipartResponseDelegate.
964         client_info->data_offset = 0;
965         return;
966       }
967       int64 upper_bound = 0, instance_size = 0;
968       // Single range requested - go through original processing for
969       // non-multipart requests, but update data offset.
970       MultipartResponseDelegate::ReadContentRanges(response,
971                                                    &client_info->data_offset,
972                                                    &upper_bound,
973                                                    &instance_size);
974     } else if (response.httpStatusCode() == kHttpResponseSuccessStatusCode) {
975       RenderThreadImpl::current()->RecordAction(
976           UserMetricsAction("Plugin_200ForByteRange"));
977       // If the client issued a byte range request and the server responds with
978       // HTTP 200 OK, it indicates that the server does not support byte range
979       // requests.
980       // We need to emulate Firefox behavior by doing the following:-
981       // 1. Destroy the plugin instance in the plugin process. Ensure that
982       //    existing resource requests initiated for the plugin instance
983       //    continue to remain valid.
984       // 2. Create a new plugin instance and notify it about the response
985       //    received here.
986       if (!ReinitializePluginForResponse(loader)) {
987         NOTREACHED();
988         return;
989       }
990 
991       // The server does not support byte range requests. No point in creating
992       // seekable streams.
993       request_is_seekable = false;
994 
995       delete client;
996       client = NULL;
997 
998       // Create a new resource client for this request.
999       for (size_t i = 0; i < clients_.size(); ++i) {
1000         if (clients_[i].loader.get() == loader) {
1001           WebPluginResourceClient* resource_client =
1002               delegate_->CreateResourceClient(clients_[i].id, plugin_url_, 0);
1003           clients_[i].client = resource_client;
1004           client = resource_client;
1005           break;
1006         }
1007       }
1008 
1009       DCHECK(client != NULL);
1010     }
1011   }
1012 
1013   // Calling into a plugin could result in reentrancy if the plugin yields
1014   // control to the OS like entering a modal loop etc. Prevent this by
1015   // stopping further loading until the plugin notifies us that it is ready to
1016   // accept data
1017   loader->setDefersLoading(true);
1018 
1019   client->DidReceiveResponse(
1020       response_info.mime_type,
1021       GetAllHeaders(response),
1022       response_info.expected_length,
1023       response_info.last_modified,
1024       request_is_seekable);
1025 
1026   // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
1027   // error codes in the stream header and as a result, was unaware of the
1028   // fate of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF
1029   // destroy the stream and invoke the NPP_DestroyStream function on the
1030   // plugin if the HTTP request fails.
1031   const GURL& url = response.url();
1032   if (url.SchemeIs("http") || url.SchemeIs("https")) {
1033     if (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400) {
1034       // The plugin instance could be in the process of deletion here.
1035       // Verify if the WebPluginResourceClient instance still exists before
1036       // use.
1037       ClientInfo* client_info = GetClientInfoFromLoader(loader);
1038       if (client_info) {
1039         client_info->pending_failure_notification = true;
1040       }
1041     }
1042   }
1043 }
1044 
didReceiveData(WebURLLoader * loader,const char * buffer,int data_length,int encoded_data_length)1045 void WebPluginImpl::didReceiveData(WebURLLoader* loader,
1046                                    const char *buffer,
1047                                    int data_length,
1048                                    int encoded_data_length) {
1049   WebPluginResourceClient* client = GetClientFromLoader(loader);
1050   if (!client)
1051     return;
1052 
1053   MultiPartResponseHandlerMap::iterator index =
1054       multi_part_response_map_.find(client);
1055   if (index != multi_part_response_map_.end()) {
1056     MultipartResponseDelegate* multi_part_handler = (*index).second;
1057     DCHECK(multi_part_handler != NULL);
1058     multi_part_handler->OnReceivedData(buffer,
1059                                        data_length,
1060                                        encoded_data_length);
1061   } else {
1062     loader->setDefersLoading(true);
1063     ClientInfo* client_info = GetClientInfoFromLoader(loader);
1064     client->DidReceiveData(buffer, data_length, client_info->data_offset);
1065     client_info->data_offset += data_length;
1066   }
1067 }
1068 
didFinishLoading(WebURLLoader * loader,double finishTime)1069 void WebPluginImpl::didFinishLoading(WebURLLoader* loader, double finishTime) {
1070   ClientInfo* client_info = GetClientInfoFromLoader(loader);
1071   if (client_info && client_info->client) {
1072     MultiPartResponseHandlerMap::iterator index =
1073       multi_part_response_map_.find(client_info->client);
1074     if (index != multi_part_response_map_.end()) {
1075       delete (*index).second;
1076       multi_part_response_map_.erase(index);
1077       DidStopLoading();
1078     }
1079     loader->setDefersLoading(true);
1080     WebPluginResourceClient* resource_client = client_info->client;
1081     // The ClientInfo can get deleted in the call to DidFinishLoading below.
1082     // It is not safe to access this structure after that.
1083     client_info->client = NULL;
1084     resource_client->DidFinishLoading(client_info->id);
1085   }
1086 }
1087 
didFail(WebURLLoader * loader,const WebURLError & error)1088 void WebPluginImpl::didFail(WebURLLoader* loader,
1089                             const WebURLError& error) {
1090   ClientInfo* client_info = GetClientInfoFromLoader(loader);
1091   if (client_info && client_info->client) {
1092     loader->setDefersLoading(true);
1093     WebPluginResourceClient* resource_client = client_info->client;
1094     // The ClientInfo can get deleted in the call to DidFail below.
1095     // It is not safe to access this structure after that.
1096     client_info->client = NULL;
1097     resource_client->DidFail(client_info->id);
1098   }
1099 }
1100 
RemoveClient(size_t i)1101 void WebPluginImpl::RemoveClient(size_t i) {
1102   clients_.erase(clients_.begin() + i);
1103 }
1104 
RemoveClient(WebURLLoader * loader)1105 void WebPluginImpl::RemoveClient(WebURLLoader* loader) {
1106   for (size_t i = 0; i < clients_.size(); ++i) {
1107     if (clients_[i].loader.get() == loader) {
1108       RemoveClient(i);
1109       return;
1110     }
1111   }
1112 }
1113 
SetContainer(WebPluginContainer * container)1114 void WebPluginImpl::SetContainer(WebPluginContainer* container) {
1115   if (!container)
1116     TearDownPluginInstance(NULL);
1117   container_ = container;
1118   if (container_)
1119     container_->allowScriptObjects();
1120 }
1121 
HandleURLRequest(const char * url,const char * method,const char * target,const char * buf,unsigned int len,int notify_id,bool popups_allowed,bool notify_redirects)1122 void WebPluginImpl::HandleURLRequest(const char* url,
1123                                      const char* method,
1124                                      const char* target,
1125                                      const char* buf,
1126                                      unsigned int len,
1127                                      int notify_id,
1128                                      bool popups_allowed,
1129                                      bool notify_redirects) {
1130   // GetURL/PostURL requests initiated explicitly by plugins should specify the
1131   // plugin SRC url as the referrer if it is available.
1132   HandleURLRequestInternal(
1133       url, method, target, buf, len, notify_id, popups_allowed, PLUGIN_SRC,
1134       notify_redirects, false);
1135 }
1136 
HandleURLRequestInternal(const char * url,const char * method,const char * target,const char * buf,unsigned int len,int notify_id,bool popups_allowed,Referrer referrer_flag,bool notify_redirects,bool is_plugin_src_load)1137 void WebPluginImpl::HandleURLRequestInternal(const char* url,
1138                                              const char* method,
1139                                              const char* target,
1140                                              const char* buf,
1141                                              unsigned int len,
1142                                              int notify_id,
1143                                              bool popups_allowed,
1144                                              Referrer referrer_flag,
1145                                              bool notify_redirects,
1146                                              bool is_plugin_src_load) {
1147   // For this request, we either route the output to a frame
1148   // because a target has been specified, or we handle the request
1149   // here, i.e. by executing the script if it is a javascript url
1150   // or by initiating a download on the URL, etc. There is one special
1151   // case in that the request is a javascript url and the target is "_self",
1152   // in which case we route the output to the plugin rather than routing it
1153   // to the plugin's frame.
1154   bool is_javascript_url = url_util::FindAndCompareScheme(
1155       url, strlen(url), "javascript", NULL);
1156   RoutingStatus routing_status = RouteToFrame(
1157       url, is_javascript_url, popups_allowed, method, target, buf, len,
1158       notify_id, referrer_flag);
1159   if (routing_status == ROUTED)
1160     return;
1161 
1162   if (is_javascript_url) {
1163     GURL gurl(url);
1164     WebString result = container_->executeScriptURL(gurl, popups_allowed);
1165 
1166     // delegate_ could be NULL because executeScript caused the container to
1167     // be deleted.
1168     if (delegate_) {
1169       delegate_->SendJavaScriptStream(
1170           gurl, result.utf8(), !result.isNull(), notify_id);
1171     }
1172 
1173     return;
1174   }
1175 
1176   unsigned long resource_id = GetNextResourceId();
1177   if (!resource_id)
1178     return;
1179 
1180   GURL complete_url = CompleteURL(url);
1181   // Remove when flash bug is fixed. http://crbug.com/40016.
1182   if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
1183     return;
1184 
1185   // If the RouteToFrame call returned a failure then inform the result
1186   // back to the plugin asynchronously.
1187   if ((routing_status == INVALID_URL) ||
1188       (routing_status == GENERAL_FAILURE)) {
1189     WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
1190         resource_id, complete_url, notify_id);
1191     if (resource_client)
1192       resource_client->DidFail(resource_id);
1193     return;
1194   }
1195 
1196   // CreateResourceClient() sends a synchronous IPC message so it's possible
1197   // that TearDownPluginInstance() may have been called in the nested
1198   // message loop.  If so, don't start the request.
1199   if (!delegate_)
1200     return;
1201 
1202   if (!CommandLine::ForCurrentProcess()->HasSwitch(
1203           switches::kDisableDirectNPAPIRequests)) {
1204     // We got here either because the plugin called GetURL/PostURL, or because
1205     // we're fetching the data for an embed tag. If we're in multi-process mode,
1206     // we want to fetch the data in the plugin process as the renderer won't be
1207     // able to request any origin when site isolation is in place. So bounce
1208     // this request back to the plugin process which will use ResourceDispatcher
1209     // to fetch the url.
1210 
1211     // TODO(jam): any better way of getting this? Can't find a way to get
1212     // frame()->loader()->outgoingReferrer() which
1213     // WebFrameImpl::setReferrerForRequest does.
1214     WebURLRequest request(complete_url);
1215     SetReferrer(&request, referrer_flag);
1216     GURL referrer(
1217         request.httpHeaderField(WebString::fromUTF8("Referer")).utf8());
1218 
1219     GURL first_party_for_cookies = webframe_->document().firstPartyForCookies();
1220     delegate_->FetchURL(resource_id, notify_id, complete_url,
1221                         first_party_for_cookies, method, buf, len, referrer,
1222                         notify_redirects, is_plugin_src_load, 0,
1223                         render_view_->routing_id());
1224   } else {
1225     WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
1226         resource_id, complete_url, notify_id);
1227     if (!resource_client)
1228       return;
1229     InitiateHTTPRequest(resource_id, resource_client, complete_url, method, buf,
1230                         len, NULL, referrer_flag, notify_redirects,
1231                         is_plugin_src_load);
1232   }
1233 }
1234 
GetNextResourceId()1235 unsigned long WebPluginImpl::GetNextResourceId() {
1236   if (!webframe_)
1237     return 0;
1238   WebView* view = webframe_->view();
1239   if (!view)
1240     return 0;
1241   return view->createUniqueIdentifierForRequest();
1242 }
1243 
InitiateHTTPRequest(unsigned long resource_id,WebPluginResourceClient * client,const GURL & url,const char * method,const char * buf,int buf_len,const char * range_info,Referrer referrer_flag,bool notify_redirects,bool is_plugin_src_load)1244 bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id,
1245                                         WebPluginResourceClient* client,
1246                                         const GURL& url,
1247                                         const char* method,
1248                                         const char* buf,
1249                                         int buf_len,
1250                                         const char* range_info,
1251                                         Referrer referrer_flag,
1252                                         bool notify_redirects,
1253                                         bool is_plugin_src_load) {
1254   if (!client) {
1255     NOTREACHED();
1256     return false;
1257   }
1258 
1259   ClientInfo info;
1260   info.id = resource_id;
1261   info.client = client;
1262   info.request.initialize();
1263   info.request.setURL(url);
1264   info.request.setFirstPartyForCookies(
1265       webframe_->document().firstPartyForCookies());
1266   info.request.setRequestorProcessID(delegate_->GetProcessId());
1267   info.request.setTargetType(WebURLRequest::TargetIsObject);
1268   info.request.setHTTPMethod(WebString::fromUTF8(method));
1269   info.pending_failure_notification = false;
1270   info.notify_redirects = notify_redirects;
1271   info.is_plugin_src_load = is_plugin_src_load;
1272   info.data_offset = 0;
1273 
1274   if (range_info) {
1275     info.request.addHTTPHeaderField(WebString::fromUTF8("Range"),
1276                                     WebString::fromUTF8(range_info));
1277   }
1278 
1279   if (strcmp(method, "POST") == 0) {
1280     // Adds headers or form data to a request.  This must be called before
1281     // we initiate the actual request.
1282     SetPostData(&info.request, buf, buf_len);
1283   }
1284 
1285   SetReferrer(&info.request, referrer_flag);
1286 
1287   WebURLLoaderOptions options;
1288   options.allowCredentials = true;
1289   options.crossOriginRequestPolicy =
1290       WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
1291   info.loader.reset(webframe_->createAssociatedURLLoader(options));
1292   if (!info.loader.get())
1293     return false;
1294   info.loader->loadAsynchronously(info.request, this);
1295 
1296   clients_.push_back(info);
1297   return true;
1298 }
1299 
CancelDocumentLoad()1300 void WebPluginImpl::CancelDocumentLoad() {
1301   if (webframe_) {
1302     ignore_response_error_ = true;
1303     webframe_->stopLoading();
1304   }
1305 }
1306 
InitiateHTTPRangeRequest(const char * url,const char * range_info,int range_request_id)1307 void WebPluginImpl::InitiateHTTPRangeRequest(
1308     const char* url, const char* range_info, int range_request_id) {
1309   unsigned long resource_id = GetNextResourceId();
1310   if (!resource_id)
1311     return;
1312 
1313   GURL complete_url = CompleteURL(url);
1314   // Remove when flash bug is fixed. http://crbug.com/40016.
1315   if (!WebPluginImpl::IsValidUrl(complete_url,
1316                                  load_manually_ ? NO_REFERRER : PLUGIN_SRC))
1317     return;
1318 
1319   WebPluginResourceClient* resource_client =
1320       delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
1321   InitiateHTTPRequest(
1322       resource_id, resource_client, complete_url, "GET", NULL, 0, range_info,
1323       load_manually_ ? NO_REFERRER : PLUGIN_SRC, false, false);
1324 }
1325 
DidStartLoading()1326 void WebPluginImpl::DidStartLoading() {
1327   if (render_view_.get()) {
1328     // TODO(darin): Make is_loading_ be a counter!
1329     render_view_->didStartLoading();
1330   }
1331 }
1332 
DidStopLoading()1333 void WebPluginImpl::DidStopLoading() {
1334   if (render_view_.get()) {
1335     // TODO(darin): Make is_loading_ be a counter!
1336     render_view_->didStopLoading();
1337   }
1338 }
1339 
SetDeferResourceLoading(unsigned long resource_id,bool defer)1340 void WebPluginImpl::SetDeferResourceLoading(unsigned long resource_id,
1341                                             bool defer) {
1342   std::vector<ClientInfo>::iterator client_index = clients_.begin();
1343   while (client_index != clients_.end()) {
1344     ClientInfo& client_info = *client_index;
1345 
1346     if (client_info.id == resource_id) {
1347       client_info.loader->setDefersLoading(defer);
1348 
1349       // If we determined that the request had failed via the HTTP headers
1350       // in the response then we send out a failure notification to the
1351       // plugin process, as certain plugins don't handle HTTP failure codes
1352       // correctly.
1353       if (!defer && client_info.client &&
1354           client_info.pending_failure_notification) {
1355         // The ClientInfo and the iterator can become invalid due to the call
1356         // to DidFail below.
1357         WebPluginResourceClient* resource_client = client_info.client;
1358         client_info.loader->cancel();
1359         clients_.erase(client_index++);
1360         resource_client->DidFail(resource_id);
1361       }
1362       break;
1363     }
1364     client_index++;
1365   }
1366 }
1367 
IsOffTheRecord()1368 bool WebPluginImpl::IsOffTheRecord() {
1369   return false;
1370 }
1371 
HandleHttpMultipartResponse(const WebURLResponse & response,WebPluginResourceClient * client)1372 bool WebPluginImpl::HandleHttpMultipartResponse(
1373     const WebURLResponse& response, WebPluginResourceClient* client) {
1374   std::string multipart_boundary;
1375   if (!MultipartResponseDelegate::ReadMultipartBoundary(
1376           response, &multipart_boundary)) {
1377     return false;
1378   }
1379 
1380   DidStartLoading();
1381 
1382   MultiPartResponseClient* multi_part_response_client =
1383       new MultiPartResponseClient(client);
1384 
1385   MultipartResponseDelegate* multi_part_response_handler =
1386       new MultipartResponseDelegate(multi_part_response_client, NULL,
1387                                     response,
1388                                     multipart_boundary);
1389   multi_part_response_map_[client] = multi_part_response_handler;
1390   return true;
1391 }
1392 
ReinitializePluginForResponse(WebURLLoader * loader)1393 bool WebPluginImpl::ReinitializePluginForResponse(
1394     WebURLLoader* loader) {
1395   WebFrame* webframe = webframe_;
1396   if (!webframe)
1397     return false;
1398 
1399   WebView* webview = webframe->view();
1400   if (!webview)
1401     return false;
1402 
1403   WebPluginContainer* container_widget = container_;
1404 
1405   // Destroy the current plugin instance.
1406   TearDownPluginInstance(loader);
1407 
1408   container_ = container_widget;
1409   webframe_ = webframe;
1410 
1411   WebPluginDelegate* plugin_delegate = CreatePluginDelegate();
1412 
1413   // Store the plugin's unique identifier, used by the container to track its
1414   // script objects, and enable script objects (since Initialize may use them
1415   // even if it fails).
1416   npp_ = plugin_delegate->GetPluginNPP();
1417   container_->allowScriptObjects();
1418 
1419   bool ok = plugin_delegate && plugin_delegate->Initialize(
1420       plugin_url_, arg_names_, arg_values_, load_manually_);
1421 
1422   if (!ok) {
1423     container_->clearScriptObjects();
1424     container_ = NULL;
1425     // TODO(iyengar) Should we delete the current plugin instance here?
1426     return false;
1427   }
1428 
1429   delegate_ = plugin_delegate;
1430 
1431   // Force a geometry update to occur to ensure that the plugin becomes
1432   // visible.
1433   container_->reportGeometry();
1434 
1435   // The plugin move sequences accumulated via DidMove are sent to the browser
1436   // whenever the renderer paints. Force a paint here to ensure that changes
1437   // to the plugin window are propagated to the browser.
1438   container_->invalidate();
1439   return true;
1440 }
1441 
TearDownPluginInstance(WebURLLoader * loader_to_ignore)1442 void WebPluginImpl::TearDownPluginInstance(
1443     WebURLLoader* loader_to_ignore) {
1444   // JavaScript garbage collection may cause plugin script object references to
1445   // be retained long after the plugin is destroyed. Some plugins won't cope
1446   // with their objects being released after they've been destroyed, and once
1447   // we've actually unloaded the plugin the object's releaseobject() code may
1448   // no longer be in memory. The container tracks the plugin's objects and lets
1449   // us invalidate them, releasing the references to them held by the JavaScript
1450   // runtime.
1451   if (container_) {
1452     container_->clearScriptObjects();
1453     container_->setWebLayer(NULL);
1454   }
1455 
1456   // Call PluginDestroyed() first to prevent the plugin from calling us back
1457   // in the middle of tearing down the render tree.
1458   if (delegate_) {
1459     // The plugin may call into the browser and pass script objects even during
1460     // teardown, so temporarily re-enable plugin script objects.
1461     DCHECK(container_);
1462     container_->allowScriptObjects();
1463 
1464     delegate_->PluginDestroyed();
1465     delegate_ = NULL;
1466 
1467     // Invalidate any script objects created during teardown here, before the
1468     // plugin might actually be unloaded.
1469     container_->clearScriptObjects();
1470   }
1471 
1472   // Cancel any pending requests because otherwise this deleted object will
1473   // be called by the ResourceDispatcher.
1474   std::vector<ClientInfo>::iterator client_index = clients_.begin();
1475   while (client_index != clients_.end()) {
1476     ClientInfo& client_info = *client_index;
1477 
1478     if (loader_to_ignore == client_info.loader) {
1479       client_index++;
1480       continue;
1481     }
1482 
1483     if (client_info.loader.get())
1484       client_info.loader->cancel();
1485 
1486     client_index = clients_.erase(client_index);
1487   }
1488 
1489   // This needs to be called now and not in the destructor since the
1490   // webframe_ might not be valid anymore.
1491   webframe_ = NULL;
1492   weak_factory_.InvalidateWeakPtrs();
1493 }
1494 
SetReferrer(blink::WebURLRequest * request,Referrer referrer_flag)1495 void WebPluginImpl::SetReferrer(blink::WebURLRequest* request,
1496                                 Referrer referrer_flag) {
1497   switch (referrer_flag) {
1498     case DOCUMENT_URL:
1499       webframe_->setReferrerForRequest(*request, GURL());
1500       break;
1501 
1502     case PLUGIN_SRC:
1503       webframe_->setReferrerForRequest(*request, plugin_url_);
1504       break;
1505 
1506     default:
1507       break;
1508   }
1509 }
1510 
1511 }  // namespace content
1512