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