diff options
-rw-r--r-- | chrome/common/plugin_messages.h | 7 | ||||
-rw-r--r-- | chrome/plugin/webplugin_delegate_stub.cc | 1 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_proxy.cc | 14 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_instance.cc | 2 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_stream.cc | 5 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_stream.h | 5 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_stream_url.cc | 4 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_stream_url.h | 4 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_string_stream.cc | 2 | ||||
-rw-r--r-- | webkit/glue/webframeloaderclient_impl.cc | 2 | ||||
-rw-r--r-- | webkit/glue/webplugin.h | 4 | ||||
-rw-r--r-- | webkit/glue/webplugin_impl.cc | 201 | ||||
-rw-r--r-- | webkit/glue/webplugin_impl.h | 29 | ||||
-rw-r--r-- | webkit/glue/webplugin_impl_mac.mm | 3 |
14 files changed, 234 insertions, 49 deletions
diff --git a/chrome/common/plugin_messages.h b/chrome/common/plugin_messages.h index 6ebead6..025acc2 100644 --- a/chrome/common/plugin_messages.h +++ b/chrome/common/plugin_messages.h @@ -69,6 +69,7 @@ struct PluginMsg_DidReceiveResponseParams { std::string headers; uint32 expected_length; uint32 last_modified; + bool request_is_seekable; }; struct NPIdentifier_Param { @@ -266,6 +267,7 @@ struct ParamTraits<PluginMsg_DidReceiveResponseParams> { WriteParam(m, p.headers); WriteParam(m, p.expected_length); WriteParam(m, p.last_modified); + WriteParam(m, p.request_is_seekable); } static bool Read(const Message* m, void** iter, param_type* r) { return @@ -273,7 +275,8 @@ struct ParamTraits<PluginMsg_DidReceiveResponseParams> { ReadParam(m, iter, &r->mime_type) && ReadParam(m, iter, &r->headers) && ReadParam(m, iter, &r->expected_length) && - ReadParam(m, iter, &r->last_modified); + ReadParam(m, iter, &r->last_modified) && + ReadParam(m, iter, &r->request_is_seekable); } static void Log(const param_type& p, std::wstring* l) { l->append(L"("); @@ -286,6 +289,8 @@ struct ParamTraits<PluginMsg_DidReceiveResponseParams> { LogParam(p.expected_length, l); l->append(L", "); LogParam(p.last_modified, l); + l->append(L", "); + LogParam(p.request_is_seekable, l); l->append(L")"); } }; diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc index 11703b6..1fc89cb 100644 --- a/chrome/plugin/webplugin_delegate_stub.cc +++ b/chrome/plugin/webplugin_delegate_stub.cc @@ -157,6 +157,7 @@ void WebPluginDelegateStub::OnDidReceiveResponse( params.headers, params.expected_length, params.last_modified, + params.request_is_seekable, cancel); } diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index 3525a1f..3bad2e4f 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -37,7 +37,8 @@ class ResourceClientProxy : public WebPluginResourceClient { public: ResourceClientProxy(PluginChannelHost* channel, int instance_id) : channel_(channel), instance_id_(instance_id), resource_id_(0), - notify_needed_(false), notify_data_(NULL) { + notify_needed_(false), notify_data_(NULL), + multibyte_response_expected_(false) { } ~ResourceClientProxy() { @@ -57,6 +58,8 @@ class ResourceClientProxy : public WebPluginResourceClient { params.notify_data = notify_data_; params.stream = existing_stream; + multibyte_response_expected_ = (existing_stream != NULL); + channel_->Send(new PluginMsg_HandleURLRequestReply(instance_id_, params)); } @@ -71,6 +74,7 @@ class ResourceClientProxy : public WebPluginResourceClient { const std::string& headers, uint32 expected_length, uint32 last_modified, + bool request_is_seekable, bool* cancel) { DCHECK(channel_ != NULL); PluginMsg_DidReceiveResponseParams params; @@ -79,6 +83,7 @@ class ResourceClientProxy : public WebPluginResourceClient { params.headers = headers; params.expected_length = expected_length; params.last_modified = last_modified; + params.request_is_seekable = request_is_seekable; // Grab a reference on the underlying channel so it does not get // deleted from under us. scoped_refptr<PluginChannelHost> channel_ref(channel_); @@ -113,6 +118,10 @@ class ResourceClientProxy : public WebPluginResourceClient { MessageLoop::current()->DeleteSoon(FROM_HERE, this); } + bool IsMultiByteResponseExpected() { + return multibyte_response_expected_; + } + private: int resource_id_; int instance_id_; @@ -120,6 +129,9 @@ private: std::string url_; bool notify_needed_; void* notify_data_; + // Set to true if the response expected is a multibyte response. + // For e.g. response for a HTTP byte range request. + bool multibyte_response_expected_; }; WebPluginDelegateProxy* WebPluginDelegateProxy::Create( diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc index 364274d6..47bf680 100644 --- a/webkit/glue/plugins/plugin_instance.cc +++ b/webkit/glue/plugins/plugin_instance.cc @@ -368,7 +368,7 @@ void PluginInstance::DidReceiveManualResponse(const std::string& url, plugin_data_stream_ = CreateStream(-1, url, mime_type, false, NULL); plugin_data_stream_->DidReceiveResponse(mime_type, headers, expected_length, - last_modified, &cancel); + last_modified, true, &cancel); AddStream(plugin_data_stream_.get()); } diff --git a/webkit/glue/plugins/plugin_stream.cc b/webkit/glue/plugins/plugin_stream.cc index bc12ace..a2b3980 100644 --- a/webkit/glue/plugins/plugin_stream.cc +++ b/webkit/glue/plugins/plugin_stream.cc @@ -25,7 +25,8 @@ PluginStream::~PluginStream() { bool PluginStream::Open(const std::string &mime_type, const std::string &headers, uint32 length, - uint32 last_modified) { + uint32 last_modified, + bool request_is_seekable) { headers_ = headers; NPP id = instance_->npp(); stream_.end = length; @@ -35,7 +36,7 @@ bool PluginStream::Open(const std::string &mime_type, stream_.notifyData = notify_data_; bool seekable_stream = false; - if (!headers_.empty()) { + if (request_is_seekable && !headers_.empty()) { stream_.headers = headers_.c_str(); if (headers_.find("Accept-Ranges: bytes") != std::string::npos) { seekable_stream = true; diff --git a/webkit/glue/plugins/plugin_stream.h b/webkit/glue/plugins/plugin_stream.h index 7b1250f..5cdc5b4 100644 --- a/webkit/glue/plugins/plugin_stream.h +++ b/webkit/glue/plugins/plugin_stream.h @@ -39,10 +39,13 @@ class PluginStream : public base::RefCounted<PluginStream> { // mime-types table and the extension (if any) in the URL. // If the size of the stream is known, use length to set the size. If // not known, set length to 0. + // The request_is_seekable parameter indicates whether byte range requests + // can be issued on the stream. bool Open(const std::string &mime_type, const std::string &headers, uint32 length, - uint32 last_modified); + uint32 last_modified, + bool request_is_seekable); // Writes to the stream. int Write(const char *buf, const int len, int data_offset); diff --git a/webkit/glue/plugins/plugin_stream_url.cc b/webkit/glue/plugins/plugin_stream_url.cc index c749ff7..f7e8ec7 100644 --- a/webkit/glue/plugins/plugin_stream_url.cc +++ b/webkit/glue/plugins/plugin_stream_url.cc @@ -42,11 +42,13 @@ void PluginStreamUrl::DidReceiveResponse(const std::string& mime_type, const std::string& headers, uint32 expected_length, uint32 last_modified, + bool request_is_seekable, bool* cancel) { bool opened = Open(mime_type, headers, expected_length, - last_modified); + last_modified, + request_is_seekable); if (!opened) { instance()->RemoveStream(this); *cancel = true; diff --git a/webkit/glue/plugins/plugin_stream_url.h b/webkit/glue/plugins/plugin_stream_url.h index 1f8c4c5..db5d4a5 100644 --- a/webkit/glue/plugins/plugin_stream_url.h +++ b/webkit/glue/plugins/plugin_stream_url.h @@ -48,10 +48,14 @@ class PluginStreamUrl : public PluginStream, const std::string& headers, uint32 expected_length, uint32 last_modified, + bool request_is_seekable, bool* cancel); void DidReceiveData(const char* buffer, int length, int data_offset); void DidFinishLoading(); void DidFail(); + bool IsMultiByteResponseExpected() { + return seekable(); + } private: diff --git a/webkit/glue/plugins/plugin_string_stream.cc b/webkit/glue/plugins/plugin_string_stream.cc index b1ad8d1..db46d1c 100644 --- a/webkit/glue/plugins/plugin_string_stream.cc +++ b/webkit/glue/plugins/plugin_string_stream.cc @@ -20,7 +20,7 @@ PluginStringStream::~PluginStringStream() { void PluginStringStream::SendToPlugin(const std::string &data, const std::string &mime_type) { int length = static_cast<int>(data.length()); - if (Open(mime_type, std::string(), length, 0)) { + if (Open(mime_type, std::string(), length, 0, false)) { // TODO - check if it was not fully sent, and figure out a backup plan. int written = Write(data.c_str(), length, 0); NPReason reason = written == length ? NPRES_DONE : NPRES_NETWORK_ERR; diff --git a/webkit/glue/webframeloaderclient_impl.cc b/webkit/glue/webframeloaderclient_impl.cc index 21b3938..0fbb4af 100644 --- a/webkit/glue/webframeloaderclient_impl.cc +++ b/webkit/glue/webframeloaderclient_impl.cc @@ -1404,7 +1404,7 @@ Widget* WebFrameLoaderClient::createPlugin(const IntSize& size, // TODO(erikkay) Widget* result = WebPluginImpl::Create(gurl, argn, argv, argc, element, webframe_, plugin_delegate, - load_manually); + load_manually, actual_mime_type); DeleteToArray(argn); DeleteToArray(argv); diff --git a/webkit/glue/webplugin.h b/webkit/glue/webplugin.h index b704153..8124857 100644 --- a/webkit/glue/webplugin.h +++ b/webkit/glue/webplugin.h @@ -148,15 +148,19 @@ class WebPluginResourceClient { public: virtual ~WebPluginResourceClient() {} virtual void WillSendRequest(const GURL& url) = 0; + // The request_is_seekable parameter indicates whether byte range requests + // can be issued for the underlying stream. virtual void DidReceiveResponse(const std::string& mime_type, const std::string& headers, uint32 expected_length, uint32 last_modified, + bool request_is_seekable, bool* cancel) = 0; virtual void DidReceiveData(const char* buffer, int length, int data_offset) = 0; virtual void DidFinishLoading() = 0; virtual void DidFail() = 0; + virtual bool IsMultiByteResponseExpected() = 0; }; diff --git a/webkit/glue/webplugin_impl.cc b/webkit/glue/webplugin_impl.cc index 221f0e2..15685e4 100644 --- a/webkit/glue/webplugin_impl.cc +++ b/webkit/glue/webplugin_impl.cc @@ -283,9 +283,11 @@ WebCore::Widget* WebPluginImpl::Create(const GURL& url, WebCore::Element *element, WebFrameImpl *frame, WebPluginDelegate* delegate, - bool load_manually) { + bool load_manually, + const std::string& mime_type) { WebPluginImpl* webplugin = new WebPluginImpl(element, frame, delegate, url, - load_manually); + load_manually, mime_type, argc, + argn, argv); if (!delegate->Initialize(url, argn, argv, argc, webplugin, load_manually)) { delegate->PluginDestroyed(); @@ -303,7 +305,11 @@ WebPluginImpl::WebPluginImpl(WebCore::Element* element, WebFrameImpl* webframe, WebPluginDelegate* delegate, const GURL& plugin_url, - bool load_manually) + bool load_manually, + const std::string& mime_type, + int arg_count, + char** arg_names, + char** arg_values) : windowless_(false), window_(NULL), element_(element), @@ -315,7 +321,11 @@ WebPluginImpl::WebPluginImpl(WebCore::Element* element, widget_(NULL), plugin_url_(plugin_url), load_manually_(load_manually), - first_geometry_update_(true) { + first_geometry_update_(true), + mime_type_(mime_type) { + + ArrayToVector(arg_count, arg_names, &arg_names_); + ArrayToVector(arg_count, arg_values, &arg_values_); } WebPluginImpl::~WebPluginImpl() { @@ -976,6 +986,7 @@ std::wstring WebPluginImpl::GetAllHeaders( void WebPluginImpl::didReceiveResponse(WebCore::ResourceHandle* handle, const WebCore::ResourceResponse& response) { static const int kHttpPartialResponseStatusCode = 206; + static const int kHttpResponseSuccessStatusCode = 200; WebPluginResourceClient* client = GetClientFromHandle(handle); if (!client) @@ -985,17 +996,55 @@ void WebPluginImpl::didReceiveResponse(WebCore::ResourceHandle* handle, WebPluginContainer::ReadHttpResponseInfo(response, &http_response_info); bool cancel = false; + bool request_is_seekable = true; + if (client->IsMultiByteResponseExpected()) { + if (response.httpStatusCode() == kHttpPartialResponseStatusCode) { + HandleHttpMultipartResponse(response, client); + return; + } else if (response.httpStatusCode() == kHttpResponseSuccessStatusCode) { + // If the client issued a byte range request and the server responds with + // HTTP 200 OK, it indicates that the server does not support byte range + // requests. + // We need to emulate Firefox behavior by doing the following:- + // 1. Destroy the plugin instance in the plugin process. Ensure that + // existing resource requests initiated for the plugin instance + // continue to remain valid. + // 2. Create a new plugin instance and notify it about the response + // received here. + if (!ReinitializePluginForResponse(handle)) { + NOTREACHED(); + return; + } - if (response.httpStatusCode() == kHttpPartialResponseStatusCode) { - HandleHttpMultipartResponse(response, client); - return; + // The server does not support byte range requests. No point in creating + // seekable streams. + request_is_seekable = false; + + delete client; + client = NULL; + + // Create a new resource client for this request. + for (size_t i = 0; i < clients_.size(); ++i) { + if (clients_[i].handle.get() == handle) { + WebPluginResourceClient* resource_client = + delegate_->CreateResourceClient(clients_[i].id, + plugin_url_.spec().c_str(), + NULL, false, NULL); + clients_[i].client = resource_client; + client = resource_client; + break; + } + } + + DCHECK(client != NULL); + } } client->DidReceiveResponse( base::SysWideToNativeMB(http_response_info.mime_type), base::SysWideToNativeMB(GetAllHeaders(response)), http_response_info.expected_length, - http_response_info.last_modified, &cancel); + http_response_info.last_modified, request_is_seekable, &cancel); if (cancel) { handle->cancel(); @@ -1078,35 +1127,7 @@ void WebPluginImpl::RemoveClient(WebCore::ResourceHandle* handle) { void WebPluginImpl::SetContainer(WebPluginContainer* container) { if (container == NULL) { - // The frame maintains a list of JSObjects which are related to this - // plugin. Tell the frame we're gone so that it can invalidate all - // of those sub JSObjects. - if (frame()) { - ASSERT(widget_ != NULL); - frame()->script()->cleanupScriptObjectsForPlugin(widget_); - } - - // Call PluginDestroyed() first to prevent the plugin from calling us back - // in the middle of tearing down the render tree. - delegate_->PluginDestroyed(); - delegate_ = NULL; - - // Cancel any pending requests because otherwise this deleted object will be - // called by the ResourceDispatcher. - int int_offset = 0; - while (!clients_.empty()) { - if (clients_[int_offset].handle) - clients_[int_offset].handle->cancel(); - WebPluginResourceClient* resource_client = clients_[int_offset].client; - RemoveClient(int_offset); - if (resource_client) - resource_client->DidFail(); - } - - // This needs to be called now and not in the destructor since the - // webframe_ might not be valid anymore. - webframe_->set_plugin_delegate(NULL); - webframe_ = NULL; + TearDownPluginInstance(NULL); } widget_ = container; } @@ -1315,3 +1336,109 @@ void WebPluginImpl::HandleHttpMultipartResponse( multipart_boundary); multi_part_response_map_[client] = multi_part_response_handler; } + +bool WebPluginImpl::ReinitializePluginForResponse( + WebCore::ResourceHandle* response_handle) { + WebFrameImpl* web_frame = WebFrameImpl::FromFrame(frame()); + if (!web_frame) + return false; + + WebViewImpl* web_view = web_frame->webview_impl(); + if (!web_view) + return false; + + WebPluginContainer* container_widget = widget_; + + // Destroy the current plugin instance. + TearDownPluginInstance(response_handle); + + widget_ = container_widget; + webframe_ = web_frame; + // Turn off the load_manually flag as we are going to hand data off to the + // plugin. + load_manually_ = false; + + WebViewDelegate* webview_delegate = web_view->GetDelegate(); + std::string actual_mime_type; + WebPluginDelegate* plugin_delegate = + webview_delegate->CreatePluginDelegate(web_view, plugin_url_, + mime_type_, std::string(), + &actual_mime_type); + + char** arg_names = new char*[arg_names_.size()]; + char** arg_values = new char*[arg_values_.size()]; + + for (unsigned int index = 0; index < arg_names_.size(); ++index) { + arg_names[index] = const_cast<char*>(arg_names_[index].c_str()); + arg_values[index] = const_cast<char*>(arg_values_[index].c_str()); + } + + bool init_ok = plugin_delegate->Initialize(plugin_url_, arg_names, + arg_values, arg_names_.size(), + this, load_manually_); + delete[] arg_names; + delete[] arg_values; + + if (!init_ok) { + SetContainer(NULL); + // TODO(iyengar) Should we delete the current plugin instance here? + return false; + } + + mime_type_ = actual_mime_type; + delegate_ = plugin_delegate; + // Force a geometry update to occur to ensure that the plugin becomes + // visible. + widget_->frameRectsChanged(); + delegate_->FlushGeometryUpdates(); + return true; +} + +void WebPluginImpl::ArrayToVector(int total_values, char** values, + std::vector<std::string>* value_vector) { + DCHECK(value_vector != NULL); + for (int index = 0; index < total_values; ++index) { + value_vector->push_back(values[index]); + } +} + +void WebPluginImpl::TearDownPluginInstance( + WebCore::ResourceHandle* response_handle_to_ignore) { + // The frame maintains a list of JSObjects which are related to this + // plugin. Tell the frame we're gone so that it can invalidate all + // of those sub JSObjects. + if (frame()) { + ASSERT(widget_ != NULL); + frame()->script()->cleanupScriptObjectsForPlugin(widget_); + } + + // Call PluginDestroyed() first to prevent the plugin from calling us back + // in the middle of tearing down the render tree. + delegate_->PluginDestroyed(); + delegate_ = NULL; + + // Cancel any pending requests because otherwise this deleted object will + // be called by the ResourceDispatcher. + std::vector<ClientInfo>::iterator client_index = clients_.begin(); + while (client_index != clients_.end()) { + ClientInfo& client_info = *client_index; + + if (response_handle_to_ignore == client_info.handle) { + client_index++; + continue; + } + + if (client_info.handle) + client_info.handle->cancel(); + + WebPluginResourceClient* resource_client = client_info.client; + client_index = clients_.erase(client_index); + if (resource_client) + resource_client->DidFail(); + } + + // This needs to be called now and not in the destructor since the + // webframe_ might not be valid anymore. + webframe_->set_plugin_delegate(NULL); + webframe_ = NULL; +} diff --git a/webkit/glue/webplugin_impl.h b/webkit/glue/webplugin_impl.h index 01cf7db..1d11d71 100644 --- a/webkit/glue/webplugin_impl.h +++ b/webkit/glue/webplugin_impl.h @@ -124,7 +124,8 @@ class WebPluginImpl : public WebPlugin, WebCore::Element* element, WebFrameImpl* frame, WebPluginDelegate* delegate, - bool load_manually); + bool load_manually, + const std::string& mime_type); virtual ~WebPluginImpl(); virtual NPObject* GetPluginScriptableObject(); @@ -139,7 +140,8 @@ class WebPluginImpl : public WebPlugin, WebPluginImpl(WebCore::Element *element, WebFrameImpl *frame, WebPluginDelegate* delegate, const GURL& plugin_url, - bool load_manually); + bool load_manually, const std::string& mime_type, + int arg_count, char** arg_names, char** arg_values); // WebPlugin implementation: void SetWindow(HWND window, HANDLE pump_messages_event); @@ -231,6 +233,12 @@ class WebPluginImpl : public WebPlugin, // Sets the actual Widget for the plugin. void SetContainer(WebPluginContainer* container); + // Destroys the plugin instance. + // The response_handle_to_ignore parameter if not NULL indicates the + // resource handle to be left valid during plugin shutdown. + void TearDownPluginInstance( + WebCore::ResourceHandle* response_handle_to_ignore); + WebCore::ScrollView* parent() const; // ResourceHandleClient implementation. We implement this interface in the @@ -294,6 +302,14 @@ class WebPluginImpl : public WebPlugin, void* notify_data, bool popups_allowed, bool use_plugin_src_as_referrer); + // Tears down the existing plugin instance and creates a new plugin instance + // to handle the response identified by the response_handle parameter. + bool ReinitializePluginForResponse(WebCore::ResourceHandle* response_handle); + + // Helper functions to convert an array of names/values to a vector. + static void ArrayToVector(int total_values, char** values, + std::vector<std::string>* value_vector); + struct ClientInfo { int id; WebPluginResourceClient* client; @@ -332,6 +348,15 @@ class WebPluginImpl : public WebPlugin, // Indicates if this is the first geometry update received by the plugin. bool first_geometry_update_; + // The mime type of the plugin. + std::string mime_type_; + + // Holds the list of argument names passed to the plugin. + std::vector<std::string> arg_names_; + + // Holds the list of argument values passed to the plugin. + std::vector<std::string> arg_values_; + DISALLOW_COPY_AND_ASSIGN(WebPluginImpl); }; diff --git a/webkit/glue/webplugin_impl_mac.mm b/webkit/glue/webplugin_impl_mac.mm index 1a420ea..b88dbb6 100644 --- a/webkit/glue/webplugin_impl_mac.mm +++ b/webkit/glue/webplugin_impl_mac.mm @@ -50,7 +50,8 @@ WebCore::Widget* WebPluginImpl::Create(const GURL& url, WebCore::Element* element, WebFrameImpl* frame, WebPluginDelegate* delegate, - bool load_manually) { + bool load_manually, + const std::string& mime_type) { // TODO(pinkerton): delete delegate when stubbing out? NSLog(@"WebPluginImpl::Create"); return NULL; |