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