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