diff options
29 files changed, 594 insertions, 182 deletions
diff --git a/chrome/common/plugin_messages.h b/chrome/common/plugin_messages.h index fcfa97f..cbe0b31 100644 --- a/chrome/common/plugin_messages.h +++ b/chrome/common/plugin_messages.h @@ -55,6 +55,7 @@ struct PluginMsg_URLRequestReply_Params { std::string url; bool notify_needed; HANDLE notify_data; + HANDLE stream; }; struct PluginMsg_Paint_Params { @@ -227,13 +228,15 @@ struct ParamTraits<PluginMsg_URLRequestReply_Params> { WriteParam(m, p.url); WriteParam(m, p.notify_needed); WriteParam(m, p.notify_data); + WriteParam(m, p.stream); } static bool Read(const Message* m, void** iter, param_type* p) { return ReadParam(m, iter, &p->resource_id) && ReadParam(m, iter, &p->url) && ReadParam(m, iter, &p->notify_needed) && - ReadParam(m, iter, &p->notify_data); + ReadParam(m, iter, &p->notify_data) && + ReadParam(m, iter, &p->stream); } static void Log(const param_type& p, std::wstring* l) { l->append(L"("); @@ -244,6 +247,8 @@ struct ParamTraits<PluginMsg_URLRequestReply_Params> { LogParam(p.notify_needed, l); l->append(L", "); LogParam(p.notify_data, l); + l->append(L", "); + LogParam(p.stream, l); l->append(L")"); } }; diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h index 7b4af2a..b0df3b3 100644 --- a/chrome/common/plugin_messages_internal.h +++ b/chrome/common/plugin_messages_internal.h @@ -141,9 +141,10 @@ IPC_BEGIN_MESSAGES(Plugin, 5) PluginMsg_DidReceiveResponseParams, bool /* cancel */) - IPC_SYNC_MESSAGE_ROUTED2_0(PluginMsg_DidReceiveData, + IPC_SYNC_MESSAGE_ROUTED3_0(PluginMsg_DidReceiveData, int /* id */, - std::vector<char> /* buffer */) + std::vector<char> /* buffer */, + int /* data_offset */) IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_DidFinishLoading, int /* id */) @@ -244,6 +245,14 @@ IPC_BEGIN_MESSAGES(PluginHost, 6) IPC_SYNC_MESSAGE_ROUTED0_1(PluginHostMsg_GetCPBrowsingContext, uint32 /* context */) + IPC_MESSAGE_ROUTED0(PluginHostMsg_CancelDocumentLoad) + + IPC_MESSAGE_ROUTED5(PluginHostMsg_InitiateHTTPRangeRequest, + std::string /* url */, + std::string /* range_info */, + HANDLE /* existing_stream */, + bool /* notify_needed */, + HANDLE /* notify_data */) IPC_END_MESSAGES(PluginHost) diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc index 3ae218e..047afce 100644 --- a/chrome/plugin/webplugin_delegate_stub.cc +++ b/chrome/plugin/webplugin_delegate_stub.cc @@ -163,12 +163,14 @@ void WebPluginDelegateStub::OnDidReceiveResponse( } void WebPluginDelegateStub::OnDidReceiveData(int id, - const std::vector<char>& buffer) { + const std::vector<char>& buffer, + int data_offset) { WebPluginResourceClient* client = webplugin_->GetResourceClient(id); if (!client) return; - client->DidReceiveData(&buffer.front(), static_cast<int>(buffer.size())); + client->DidReceiveData(&buffer.front(), static_cast<int>(buffer.size()), + data_offset); } void WebPluginDelegateStub::OnDidFinishLoading(int id) { @@ -426,7 +428,8 @@ void WebPluginDelegateStub::OnHandleURLRequestReply( WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(params.resource_id, params.url, params.notify_needed, - params.notify_data); + params.notify_data, + params.stream); webplugin_->OnResourceCreated(params.resource_id, resource_client); } diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h index 391334a..f113cb8 100644 --- a/chrome/plugin/webplugin_delegate_stub.h +++ b/chrome/plugin/webplugin_delegate_stub.h @@ -49,7 +49,8 @@ class WebPluginDelegateStub : public IPC::Channel::Listener, void OnWillSendRequest(int id, const GURL& url); void OnDidReceiveResponse(const PluginMsg_DidReceiveResponseParams& params, bool* cancel); - void OnDidReceiveData(int id, const std::vector<char>& buffer); + void OnDidReceiveData(int id, const std::vector<char>& buffer, + int data_offset); void OnDidFinishLoading(int id); void OnDidFail(int id); diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc index b1f3913..6f68c2d 100644 --- a/chrome/plugin/webplugin_proxy.cc +++ b/chrome/plugin/webplugin_proxy.cc @@ -243,3 +243,17 @@ void WebPluginProxy::HandleURLRequest(const char *method, Send(new PluginHostMsg_URLRequest(route_id_, params)); } +void WebPluginProxy::CancelDocumentLoad() { + Send(new PluginHostMsg_CancelDocumentLoad(route_id_)); +} + +void WebPluginProxy::InitiateHTTPRangeRequest(const char* url, + const char* range_info, + void* existing_stream, + bool notify_needed, + HANDLE notify_data) { + + Send(new PluginHostMsg_InitiateHTTPRangeRequest(route_id_, url, + range_info, existing_stream, + notify_needed, notify_data)); +} diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h index 5bad3f9..092bf32 100644 --- a/chrome/plugin/webplugin_proxy.h +++ b/chrome/plugin/webplugin_proxy.h @@ -73,6 +73,13 @@ class WebPluginProxy : public WebPlugin { bool notify, const char* url, void* notify_data, bool popups_allowed); + void CancelDocumentLoad(); + + void InitiateHTTPRangeRequest(const char* url, + const char* range_info, + void* existing_stream, + bool notify_needed, + HANDLE notify_data); private: bool Send(IPC::Message* msg); diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index 97b0788..225608e 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -44,7 +44,7 @@ class ResourceClientProxy : public WebPluginResourceClient { } void Initialize(int resource_id, const std::string &url, bool notify_needed, - void *notify_data) { + void *notify_data, void* existing_stream) { resource_id_ = resource_id; url_ = url; notify_needed_ = notify_needed; @@ -55,6 +55,7 @@ class ResourceClientProxy : public WebPluginResourceClient { params.url = url_; params.notify_needed = notify_needed_; params.notify_data = notify_data_; + params.stream = existing_stream; channel_->Send(new PluginMsg_HandleURLRequestReply(instance_id_, params)); } @@ -85,7 +86,7 @@ class ResourceClientProxy : public WebPluginResourceClient { cancel)); } - void DidReceiveData(const char* buffer, int length) { + void DidReceiveData(const char* buffer, int length, int data_offset) { DCHECK(channel_ != NULL); DCHECK(length > 0); std::vector<char> data; @@ -95,7 +96,7 @@ class ResourceClientProxy : public WebPluginResourceClient { // deleted from under us. scoped_refptr<PluginChannelHost> channel_ref(channel_); channel_->Send(new PluginMsg_DidReceiveData(instance_id_, resource_id_, - data)); + data, data_offset)); } void DidFinishLoading() { @@ -112,7 +113,7 @@ class ResourceClientProxy : public WebPluginResourceClient { MessageLoop::current()->DeleteSoon(FROM_HERE, this); } - private: +private: int resource_id_; int instance_id_; scoped_refptr<PluginChannelHost> channel_; @@ -316,6 +317,9 @@ void WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(PluginHostMsg_URLRequest, OnHandleURLRequest) IPC_MESSAGE_HANDLER(PluginHostMsg_GetCPBrowsingContext, OnGetCPBrowsingContext) + IPC_MESSAGE_HANDLER(PluginHostMsg_CancelDocumentLoad, OnCancelDocumentLoad) + IPC_MESSAGE_HANDLER(PluginHostMsg_InitiateHTTPRangeRequest, + OnInitiateHTTPRangeRequest) IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() } @@ -655,10 +659,10 @@ void WebPluginDelegateProxy::OnHandleURLRequest( WebPluginResourceClient* WebPluginDelegateProxy::CreateResourceClient( int resource_id, const std::string &url, bool notify_needed, - void *notify_data) { + void* notify_data, void* npstream) { ResourceClientProxy* proxy = new ResourceClientProxy(channel_host_, instance_id_); - proxy->Initialize(resource_id, url, notify_needed, notify_data); + proxy->Initialize(resource_id, url, notify_needed, notify_data, npstream); return proxy; } @@ -669,3 +673,14 @@ void WebPluginDelegateProxy::URLRequestRouted(const std::string& url, notify_data)); } +void WebPluginDelegateProxy::OnCancelDocumentLoad() { + plugin_->CancelDocumentLoad(); +} + +void WebPluginDelegateProxy::OnInitiateHTTPRangeRequest( + const std::string& url, const std::string& range_info, + HANDLE existing_stream, bool notify_needed, HANDLE notify_data) { + plugin_->InitiateHTTPRangeRequest(url.c_str(), range_info.c_str(), + existing_stream, notify_needed, + notify_data); +} diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h index d0f977b..5ce612a 100644 --- a/chrome/renderer/webplugin_delegate_proxy.h +++ b/chrome/renderer/webplugin_delegate_proxy.h @@ -82,7 +82,8 @@ class WebPluginDelegateProxy : public WebPluginDelegate, virtual WebPluginResourceClient* CreateResourceClient(int resource_id, const std::string &url, bool notify_needed, - void *notify_data); + void* notify_data, + void* existing_stream); // Notifies the delegate about a Get/Post URL request getting routed virtual void URLRequestRouted(const std::string&url, bool notify_needed, @@ -118,6 +119,11 @@ class WebPluginDelegateProxy : public WebPluginDelegate, std::string* json_retval); void OnMissingPluginStatus(int status); void OnGetCPBrowsingContext(uint32* context); + void OnCancelDocumentLoad(); + void OnInitiateHTTPRangeRequest(const std::string& url, + const std::string& range_info, + HANDLE existing_stream, bool notify_needed, + HANDLE notify_data); // Draw a graphic indicating a crashed plugin. void PaintSadPlugin(HDC hdc, const gfx::Rect& rect); diff --git a/webkit/build/glue/glue.vcproj b/webkit/build/glue/glue.vcproj index 9bf3e82..080bd78 100644 --- a/webkit/build/glue/glue.vcproj +++ b/webkit/build/glue/glue.vcproj @@ -609,14 +609,6 @@ > </File> <File - RelativePath="..\..\glue\plugins\plugin_data_stream.cc" - > - </File> - <File - RelativePath="..\..\glue\plugins\plugin_data_stream.h" - > - </File> - <File RelativePath="..\..\glue\plugins\plugin_host.cc" > </File> diff --git a/webkit/glue/SConscript b/webkit/glue/SConscript index aca54f3..cccc1df 100644 --- a/webkit/glue/SConscript +++ b/webkit/glue/SConscript @@ -56,7 +56,6 @@ if env['PLATFORM'] == 'win32': 'password_autocomplete_listener.cc', 'password_form_dom_manager.cc', 'plugins/mozilla_extensions.cc', - 'plugins/plugin_data_stream.cc', 'plugins/plugin_host.cc', 'plugins/plugin_instance.cc', 'plugins/plugin_lib.cc', diff --git a/webkit/glue/multipart_response_delegate.cc b/webkit/glue/multipart_response_delegate.cc index 7bef1c3..1fc9e34 100644 --- a/webkit/glue/multipart_response_delegate.cc +++ b/webkit/glue/multipart_response_delegate.cc @@ -72,6 +72,11 @@ void MultipartResponseDelegate::OnReceivedData(const char* data, int data_len) { // Headers if (processing_headers_) { + // Eat leading \r\n + int pos = PushOverLine(data_, 0); + if (pos) + data_ = data_.substr(pos); + if (ParseHeaders()) { // Successfully parsed headers. processing_headers_ = false; @@ -227,3 +232,78 @@ size_t MultipartResponseDelegate::FindBoundary() { return boundary_pos; } +bool MultipartResponseDelegate::ReadMultipartBoundary( + const WebCore::ResourceResponse& response, + std::string* multipart_boundary) { + + WebCore::String content_type = response.httpHeaderField("Content-Type"); + std::string content_type_as_string = + webkit_glue::StringToStdString(content_type); + + size_t boundary_start_offset = content_type_as_string.find("boundary="); + if (boundary_start_offset == std::wstring::npos) { + return false; + } + + boundary_start_offset += strlen("boundary="); + size_t boundary_end_offset = content_type.length(); + + size_t boundary_length = boundary_end_offset - boundary_start_offset; + + *multipart_boundary = + content_type_as_string.substr(boundary_start_offset, boundary_length); + return true; +} + +bool MultipartResponseDelegate::ReadContentRanges( + const WebCore::ResourceResponse& response, + int* content_range_lower_bound, + int* content_range_upper_bound) { + + std::string content_range = + webkit_glue::StringToStdString( + response.httpHeaderField("Content-Range")); + + size_t byte_range_lower_bound_start_offset = + content_range.find(" "); + if (byte_range_lower_bound_start_offset == std::string::npos) { + return false; + } + + // Skip over the initial space. + byte_range_lower_bound_start_offset++; + + size_t byte_range_lower_bound_end_offset = + content_range.find("-", byte_range_lower_bound_start_offset); + if (byte_range_lower_bound_end_offset == std::string::npos) { + return false; + } + + size_t byte_range_lower_bound_characters = + byte_range_lower_bound_end_offset - byte_range_lower_bound_start_offset; + std::string byte_range_lower_bound = + content_range.substr(byte_range_lower_bound_start_offset, + byte_range_lower_bound_characters); + + size_t byte_range_upper_bound_start_offset = + byte_range_lower_bound_end_offset + 1; + + size_t byte_range_upper_bound_end_offset = + content_range.find("/", byte_range_upper_bound_start_offset); + if (byte_range_upper_bound_end_offset == std::string::npos) { + return false; + } + + size_t byte_range_upper_bound_characters = + byte_range_upper_bound_end_offset - byte_range_upper_bound_start_offset; + + std::string byte_range_upper_bound = + content_range.substr(byte_range_upper_bound_start_offset, + byte_range_upper_bound_characters); + + if (!StringToInt(byte_range_lower_bound, content_range_lower_bound)) + return false; + if (!StringToInt(byte_range_upper_bound, content_range_upper_bound)) + return false; + return true; +} diff --git a/webkit/glue/multipart_response_delegate.h b/webkit/glue/multipart_response_delegate.h index f5b8109..e7c1ba4 100644 --- a/webkit/glue/multipart_response_delegate.h +++ b/webkit/glue/multipart_response_delegate.h @@ -72,6 +72,19 @@ class MultipartResponseDelegate { void OnReceivedData(const char* data, int data_len); void OnCompletedRequest(); + // Returns the multi part boundary string from the Content-type header + // in the response. + // Returns true on success. + static bool ReadMultipartBoundary(const WebCore::ResourceResponse& response, + std::string* multipart_boundary); + + // Returns the lower and higher content ranges from an individual multipart + // in a multipart response. + // Returns true on success. + static bool ReadContentRanges(const WebCore::ResourceResponse& response, + int* content_range_lower_bound, + int* content_range_upper_bound); + private: // Pointers back to our owning object so we can make callbacks as we parse // pieces of data. diff --git a/webkit/glue/multipart_response_delegate_unittest.cc b/webkit/glue/multipart_response_delegate_unittest.cc index 2e1d1f1..e5fd0c6 100644 --- a/webkit/glue/multipart_response_delegate_unittest.cc +++ b/webkit/glue/multipart_response_delegate_unittest.cc @@ -373,5 +373,94 @@ TEST(MultipartResponseTest, MultipleBoundaries) { client.data_); } +TEST(MultipartResponseTest, MultipartByteRangeParsingTest) { + // Test multipart/byteranges based boundary parsing. + ResourceResponse response1(KURL(), "multipart/byteranges", 0, "en-US", + String()); + response1.setHTTPHeaderField(String("Content-Length"), String("200")); + response1.setHTTPHeaderField( + String("Content-type"), + String("multipart/byteranges; boundary=--bound--")); + + std::string multipart_boundary; + bool result = MultipartResponseDelegate::ReadMultipartBoundary( + response1, &multipart_boundary); + EXPECT_EQ(result, true); + EXPECT_EQ(string("--bound--"), + multipart_boundary); + + ResourceResponse response2(KURL(), "image/png", 0, "en-US", + String()); + + response2.setHTTPHeaderField(String("Content-Length"), String("300")); + response2.setHTTPHeaderField( + String("Last-Modified"), + String("Mon, 04 Apr 2005 20:36:01 GMT")); + response2.setHTTPHeaderField( + String("Date"), + String("Thu, 11 Sep 2008 18:21:42 GMT")); + + multipart_boundary.clear(); + result = MultipartResponseDelegate::ReadMultipartBoundary( + response2, &multipart_boundary); + EXPECT_EQ(result, false); + + ResourceResponse response3(KURL(), "multipart/byteranges", 0, "en-US", + String()); + + response3.setHTTPHeaderField(String("Content-Length"), String("300")); + response3.setHTTPHeaderField( + String("Last-Modified"), + String("Mon, 04 Apr 2005 20:36:01 GMT")); + response3.setHTTPHeaderField( + String("Date"), + String("Thu, 11 Sep 2008 18:21:42 GMT")); + response3.setHTTPHeaderField( + String("Content-type"), + String("multipart/byteranges")); + + multipart_boundary.clear(); + result = MultipartResponseDelegate::ReadMultipartBoundary( + response3, &multipart_boundary); + EXPECT_EQ(result, false); + EXPECT_EQ(multipart_boundary.length(), 0); +} + +TEST(MultipartResponseTest, MultipartContentRangesTest) { + ResourceResponse response1(KURL(), "application/pdf", 0, "en-US", + String()); + response1.setHTTPHeaderField(String("Content-Length"), String("200")); + response1.setHTTPHeaderField( + String("Content-Range"), + String("bytes 1000-1050/5000")); + + int content_range_lower_bound = 0; + int content_range_upper_bound = 0; + + bool result = MultipartResponseDelegate::ReadContentRanges( + response1, &content_range_lower_bound, + &content_range_upper_bound); + + EXPECT_EQ(result, true); + EXPECT_EQ(content_range_lower_bound, 1000); + EXPECT_EQ(content_range_upper_bound, 1050); + + ResourceResponse response2(KURL(), "application/pdf", 0, "en-US", + String()); + response2.setHTTPHeaderField(String("Content-Length"), String("200")); + response2.setHTTPHeaderField( + String("Content-Range"), + String("bytes 1000/1050")); + + content_range_lower_bound = 0; + content_range_upper_bound = 0; + + result = MultipartResponseDelegate::ReadContentRanges( + response2, &content_range_lower_bound, + &content_range_upper_bound); + + EXPECT_EQ(result, false); +} + } // namespace diff --git a/webkit/glue/plugins/plugin_data_stream.cc b/webkit/glue/plugins/plugin_data_stream.cc deleted file mode 100644 index da5f2d5..0000000 --- a/webkit/glue/plugins/plugin_data_stream.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "webkit/glue/plugins/plugin_data_stream.h" - -#include "base/logging.h" - -namespace NPAPI { - -PluginDataStream::PluginDataStream(PluginInstance *instance, - const std::string& url, - const std::string& mime_type, - const std::string& headers, - uint32 expected_length, - uint32 last_modified) - : PluginStream(instance, url.c_str(), false, 0), - mime_type_(mime_type), - headers_(headers), - expected_length_(expected_length), - last_modified_(last_modified), - stream_open_failed_(false) { -} - -PluginDataStream::~PluginDataStream() { -} - -void PluginDataStream::SendToPlugin(const char* buffer, int length) { - if (stream_open_failed_) - return; - - if (!open()) { - if (!Open(mime_type_, headers_, expected_length_, last_modified_)) { - stream_open_failed_ = true; - return; - } - } - - // TODO(iyengar) - check if it was not fully sent, and figure out a - // backup plan. - int written = Write(buffer, length); - DCHECK(written == length); -} - -} // namespace NPAPI - diff --git a/webkit/glue/plugins/plugin_data_stream.h b/webkit/glue/plugins/plugin_data_stream.h deleted file mode 100644 index cec0074..0000000 --- a/webkit/glue/plugins/plugin_data_stream.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_DATA_STREAM_H__ -#define WEBKIT_GLUE_PLUGIN_PLUGIN_DATA_STREAM_H__ - -#include "webkit/glue/plugins/plugin_stream.h" - -namespace NPAPI { - -class PluginInstance; - -// A NPAPI stream based on data received from the renderer. -class PluginDataStream : public PluginStream { - public: - // Create a new stream for sending to the plugin. - PluginDataStream(PluginInstance *instance, const std::string& url, - const std::string& mime_type, const std::string& headers, - uint32 expected_length, uint32 last_modified); - virtual ~PluginDataStream(); - - // Initiates the sending of data to the plugin. - void SendToPlugin(const char* buffer, int length); - - private: - std::string mime_type_; - std::string headers_; - uint32 expected_length_; - uint32 last_modified_; - // This flag when set serves as an indicator that subsequent - // data coming from the renderer should not be handed off to the plugin. - bool stream_open_failed_; - - DISALLOW_EVIL_CONSTRUCTORS(PluginDataStream); -}; - -} // namespace NPAPI - -#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_DATA_STREAM_H__ - - diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc index 8b92771..273219d 100644 --- a/webkit/glue/plugins/plugin_host.cc +++ b/webkit/glue/plugins/plugin_host.cc @@ -395,10 +395,19 @@ void NPN_ReloadPlugins(NPBool reloadPages) { } // Requests a range of bytes for a seekable stream. -NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList) { - // TODO: implement me - DLOG(INFO) << "NPN_RequestedRead is not implemented yet."; - return NPERR_GENERIC_ERROR; +NPError NPN_RequestRead(NPStream* stream, NPByteRange* range_list) { + if (!stream || !range_list) { + return NPERR_GENERIC_ERROR; + } + + scoped_refptr<NPAPI::PluginInstance> plugin = + reinterpret_cast<NPAPI::PluginInstance*>(stream->ndata); + if (!plugin.get()) { + return NPERR_GENERIC_ERROR; + } + + plugin->RequestRead(stream, range_list); + return NPERR_NO_ERROR; } static bool IsJavaScriptUrl(const std::string& url) { diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc index 46b28a9..0f81412 100644 --- a/webkit/glue/plugins/plugin_instance.cc +++ b/webkit/glue/plugins/plugin_instance.cc @@ -10,7 +10,6 @@ #include "webkit/glue/glue_util.h" #include "webkit/glue/webplugin.h" #include "webkit/glue/webkit_glue.h" -#include "webkit/glue/plugins/plugin_data_stream.h" #include "webkit/glue/plugins/plugin_host.h" #include "webkit/glue/plugins/plugin_lib.h" #include "webkit/glue/plugins/plugin_stream_url.h" @@ -93,7 +92,7 @@ void PluginInstance::RemoveStream(PluginStream* stream) { std::vector<scoped_refptr<PluginStream> >::iterator stream_index; for (stream_index = open_streams_.begin(); - stream_index != open_streams_.end(); ++stream_index) { + stream_index != open_streams_.end(); ++stream_index) { if (*stream_index == stream) { open_streams_.erase(stream_index); break; @@ -356,32 +355,37 @@ void PluginInstance::DidReceiveManualResponse(const std::string& url, response_url = instance_url_.spec(); } - plugin_data_stream_ = new PluginDataStream(this, response_url, mime_type, - headers, expected_length, - last_modified); + bool cancel = false; + + plugin_data_stream_ = CreateStream(-1, url, mime_type, false, NULL); + + plugin_data_stream_->DidReceiveResponse(mime_type, headers, expected_length, + last_modified, &cancel); AddStream(plugin_data_stream_.get()); } void PluginInstance::DidReceiveManualData(const char* buffer, int length) { DCHECK(load_manually_); - DCHECK(plugin_data_stream_.get() != NULL); - plugin_data_stream_->SendToPlugin(buffer, length); + if (plugin_data_stream_.get() != NULL) { + plugin_data_stream_->DidReceiveData(buffer, length, 0); + } } void PluginInstance::DidFinishManualLoading() { DCHECK(load_manually_); - DCHECK(plugin_data_stream_); - plugin_data_stream_->Close(NPRES_DONE); - RemoveStream(plugin_data_stream_.get()); - plugin_data_stream_ = NULL; + if (plugin_data_stream_.get() != NULL) { + plugin_data_stream_->DidFinishLoading(); + plugin_data_stream_->Close(NPRES_DONE); + plugin_data_stream_ = NULL; + } } void PluginInstance::DidManualLoadFail() { DCHECK(load_manually_); - DCHECK(plugin_data_stream_); - plugin_data_stream_->Close(NPRES_NETWORK_ERR); - RemoveStream(plugin_data_stream_.get()); - plugin_data_stream_ = NULL; + if (plugin_data_stream_.get() != NULL) { + plugin_data_stream_->DidFail(); + plugin_data_stream_ = NULL; + } } void PluginInstance::PluginThreadAsyncCall(void (*func)(void *), @@ -436,5 +440,50 @@ void PluginInstance::PopPopupsEnabledState() { popups_enabled_stack_.pop(); } +void PluginInstance::RequestRead(NPStream* stream, NPByteRange* range_list) { + std::string range_info = "bytes="; + + while (range_list) { + range_info += IntToString(range_list->offset); + range_info += "-"; + range_info += IntToString(range_list->offset + range_list->length - 1); + range_list = range_list->next; + if (range_list) { + range_info += ","; + } + } + + if (plugin_data_stream_) { + if (plugin_data_stream_->stream() == stream) { + webplugin_->CancelDocumentLoad(); + plugin_data_stream_ = NULL; + } + } + + // The lifetime of a NPStream instance depends on the PluginStream instance + // which owns it. When a plugin invokes NPN_RequestRead on a seekable stream, + // we don't want to create a new stream when the corresponding response is + // received. We send over a cookie which represents the PluginStream + // instance which is sent back from the renderer when the response is + // received. + std::vector<scoped_refptr<PluginStream> >::iterator stream_index; + for (stream_index = open_streams_.begin(); + stream_index != open_streams_.end(); ++stream_index) { + PluginStream* plugin_stream = *stream_index; + if (plugin_stream->stream() == stream) { + // A stream becomes seekable the first time NPN_RequestRead + // is called on it. + plugin_stream->set_seekable(true); + + webplugin_->InitiateHTTPRangeRequest( + stream->url, range_info.c_str(), + plugin_stream, + plugin_stream->notify_needed(), + plugin_stream->notify_data()); + break; + } + } +} + } // namespace NPAPI diff --git a/webkit/glue/plugins/plugin_instance.h b/webkit/glue/plugins/plugin_instance.h index b37153b..b6b1465 100644 --- a/webkit/glue/plugins/plugin_instance.h +++ b/webkit/glue/plugins/plugin_instance.h @@ -192,6 +192,9 @@ class PluginInstance : public base::RefCounted<PluginInstance> { return popups_enabled_stack_.empty() ? false : popups_enabled_stack_.top(); } + // Initiates byte range reads for plugins. + void RequestRead(NPStream* stream, NPByteRange* range_list); + private: void OnPluginThreadAsyncCall(void (*func)(void *), void *userData); @@ -238,7 +241,7 @@ class PluginInstance : public base::RefCounted<PluginInstance> { // (MozillaExtensionApi) created as a result of NPN_GetValue // in the context of NP_Initialize. static ThreadLocalStorage::Slot plugin_instance_tls_index_; - scoped_refptr<PluginDataStream> plugin_data_stream_; + scoped_refptr<PluginStreamUrl> plugin_data_stream_; GURL instance_url_; // This flag if true indicates that the plugin data would be passed from diff --git a/webkit/glue/plugins/plugin_stream.cc b/webkit/glue/plugins/plugin_stream.cc index 2c742ff..29cc99a 100644 --- a/webkit/glue/plugins/plugin_stream.cc +++ b/webkit/glue/plugins/plugin_stream.cc @@ -22,13 +22,14 @@ PluginStream::PluginStream( bool need_notify, void *notify_data) : instance_(instance), - bytes_sent_(0), notify_needed_(need_notify), notify_data_(notify_data), close_on_write_data_(false), opened_(false), requested_plugin_mode_(NP_NORMAL), - temp_file_handle_(INVALID_HANDLE_VALUE) { + temp_file_handle_(INVALID_HANDLE_VALUE), + seekable_stream_(false), + data_offset_(0) { memset(&stream_, 0, sizeof(stream_)); stream_.url = _strdup(url); temp_file_name_[0] = '\0'; @@ -37,7 +38,6 @@ PluginStream::PluginStream( PluginStream::~PluginStream() { // always cleanup our temporary files. CleanupTempFile(); - free(const_cast<char*>(stream_.url)); } @@ -58,8 +58,14 @@ bool PluginStream::Open(const std::string &mime_type, stream_.pdata = 0; stream_.ndata = id->ndata; stream_.notifyData = notify_data_; - if (!headers_.empty()) + + bool seekable_stream = false; + if (!headers_.empty()) { stream_.headers = headers_.c_str(); + if (headers_.find("Accept-Ranges: bytes") != std::string::npos) { + seekable_stream = true; + } + } const char *char_mime_type = "application/x-unknown-content-type"; std::string temp_mime_type; @@ -75,26 +81,31 @@ bool PluginStream::Open(const std::string &mime_type, // Silverlight expects a valid mime type DCHECK(strlen(char_mime_type) != 0); NPError err = instance_->NPP_NewStream((NPMIMEType)char_mime_type, - &stream_, false, + &stream_, seekable_stream, &requested_plugin_mode_); if (err != NPERR_NO_ERROR) return false; opened_ = true; + if (requested_plugin_mode_ == NP_SEEK) { + seekable_stream_ = true; + } + // If the plugin has requested certain modes, then we need a copy // of this file on disk. Open it and save it as we go. if (requested_plugin_mode_ == NP_ASFILEONLY || - requested_plugin_mode_ == NP_ASFILE || - requested_plugin_mode_ == NP_SEEK) { + requested_plugin_mode_ == NP_ASFILE) { if (OpenTempFile() == false) return false; } + mime_type_ = char_mime_type; return true; } -int PluginStream::Write(const char *buffer, const int length) { +int PluginStream::Write(const char *buffer, const int length, + int data_offset) { // There may be two streams to write to - the plugin and the file. // It is unclear what to do if we cannot write to both. The rules of // this function are that the plugin must consume at least as many @@ -103,7 +114,8 @@ int PluginStream::Write(const char *buffer, const int length) { // to each stream, we'll return failure. DCHECK(opened_); - if (WriteToFile(buffer, length) && WriteToPlugin(buffer, length)) + if (WriteToFile(buffer, length) && + WriteToPlugin(buffer, length, data_offset)) return length; return -1; @@ -113,8 +125,7 @@ bool PluginStream::WriteToFile(const char *buf, const int length) { // For ASFILEONLY, ASFILE, and SEEK modes, we need to write // to the disk if (temp_file_handle_ != INVALID_HANDLE_VALUE && - (requested_plugin_mode_ == NP_SEEK || - requested_plugin_mode_ == NP_ASFILE || + (requested_plugin_mode_ == NP_ASFILE || requested_plugin_mode_ == NP_ASFILEONLY) ) { int totalBytesWritten = 0; DWORD bytes; @@ -131,13 +142,15 @@ bool PluginStream::WriteToFile(const char *buf, const int length) { return true; } -bool PluginStream::WriteToPlugin(const char *buf, const int length) { +bool PluginStream::WriteToPlugin(const char *buf, const int length, + const int data_offset) { // For NORMAL and ASFILE modes, we send the data to the plugin now if (requested_plugin_mode_ != NP_NORMAL && - requested_plugin_mode_ != NP_ASFILE) + requested_plugin_mode_ != NP_ASFILE && + requested_plugin_mode_ != NP_SEEK) return true; - int written = TryWriteToPlugin(buf, length); + int written = TryWriteToPlugin(buf, length, data_offset); if (written == -1) return false; @@ -146,6 +159,7 @@ bool PluginStream::WriteToPlugin(const char *buf, const int length) { size_t remaining = length - written; size_t previous_size = delivery_data_.size(); delivery_data_.resize(previous_size + remaining); + data_offset_ = data_offset; memcpy(&delivery_data_[previous_size], buf + written, remaining); MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( this, &PluginStream::OnDelayDelivery)); @@ -162,7 +176,8 @@ void PluginStream::OnDelayDelivery() { } int size = static_cast<int>(delivery_data_.size()); - int written = TryWriteToPlugin(&delivery_data_.front(), size); + int written = TryWriteToPlugin(&delivery_data_.front(), size, + data_offset_); if (written > 0) { // Remove the data that we already wrote. delivery_data_.erase(delivery_data_.begin(), @@ -170,10 +185,14 @@ void PluginStream::OnDelayDelivery() { } } -int PluginStream::TryWriteToPlugin(const char *buf, const int length) { +int PluginStream::TryWriteToPlugin(const char *buf, const int length, + const int data_offset) { bool result = true; int byte_offset = 0; + if (data_offset > 0) + data_offset_ = data_offset; + while (byte_offset < length) { int bytes_remaining = length - byte_offset; int bytes_to_write = instance_->NPP_WriteReady(&stream_); @@ -184,7 +203,7 @@ int PluginStream::TryWriteToPlugin(const char *buf, const int length) { return byte_offset; int bytes_consumed = instance_->NPP_Write( - &stream_, bytes_sent_, bytes_to_write, + &stream_, data_offset_, bytes_to_write, const_cast<char*>(buf + byte_offset)); if (bytes_consumed < 0) { // The plugin failed, which means that we need to close the stream. @@ -199,7 +218,7 @@ int PluginStream::TryWriteToPlugin(const char *buf, const int length) { // The plugin might report more that we gave it. bytes_consumed = std::min(bytes_consumed, bytes_to_write); - bytes_sent_ += bytes_consumed; + data_offset_ += bytes_consumed; byte_offset += bytes_consumed; } diff --git a/webkit/glue/plugins/plugin_stream.h b/webkit/glue/plugins/plugin_stream.h index f932be4..be9a594 100644 --- a/webkit/glue/plugins/plugin_stream.h +++ b/webkit/glue/plugins/plugin_stream.h @@ -12,6 +12,8 @@ #include "third_party/npapi/bindings/npapi.h" +class WebPluginResourceClient; + namespace NPAPI { class PluginInstance; @@ -43,7 +45,7 @@ class PluginStream : public base::RefCounted<PluginStream> { uint32 last_modified); // Writes to the stream. - int Write(const char *buf, const int len); + int Write(const char *buf, const int len, int data_offset); // Write the result as a file. void WriteAsFile(); @@ -54,9 +56,22 @@ class PluginStream : public base::RefCounted<PluginStream> { // Close the stream. virtual bool Close(NPReason reason); - const NPStream* stream() const { - return &stream_; - } + virtual WebPluginResourceClient* AsResourceClient() { return NULL; } + + // Cancels any HTTP requests initiated by the stream. + virtual void CancelRequest() {} + + const NPStream* stream() const { return &stream_; } + + // setter/getter for the seekable attribute on the stream. + bool seekable() const { return seekable_stream_; } + + void set_seekable(bool seekable) { seekable_stream_ = seekable; } + + // getters for reading the notification related attributes on the stream. + bool notify_needed() const { return notify_needed_; } + + void* notify_data() const { return notify_data_; } protected: PluginInstance* instance() { return instance_.get(); } @@ -80,11 +95,11 @@ class PluginStream : public base::RefCounted<PluginStream> { // Sends the data to the plugin. If it's not ready, handles buffering it // and retrying later. - bool WriteToPlugin(const char *buf, const int length); + bool WriteToPlugin(const char *buf, const int length, const int data_offset); // Send the data to the plugin, returning how many bytes it accepted, or -1 // if an error occurred. - int TryWriteToPlugin(const char *buf, const int length); + int TryWriteToPlugin(const char *buf, const int length, const int data_offset); // The callback which calls TryWriteToPlugin. void OnDelayDelivery(); @@ -93,7 +108,6 @@ class PluginStream : public base::RefCounted<PluginStream> { NPStream stream_; std::string headers_; scoped_refptr<PluginInstance> instance_; - int bytes_sent_; bool notify_needed_; void * notify_data_; bool close_on_write_data_; @@ -102,7 +116,9 @@ class PluginStream : public base::RefCounted<PluginStream> { char temp_file_name_[MAX_PATH]; HANDLE temp_file_handle_; std::vector<char> delivery_data_; - + int data_offset_; + bool seekable_stream_; + std::string mime_type_; DISALLOW_EVIL_CONSTRUCTORS(PluginStream); }; diff --git a/webkit/glue/plugins/plugin_stream_url.cc b/webkit/glue/plugins/plugin_stream_url.cc index eda341a..c749ff7 100644 --- a/webkit/glue/plugins/plugin_stream_url.cc +++ b/webkit/glue/plugins/plugin_stream_url.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + #include "webkit/glue/plugins/plugin_stream_url.h" #include "webkit/glue/glue_util.h" @@ -26,14 +27,7 @@ PluginStreamUrl::~PluginStreamUrl() { } bool PluginStreamUrl::Close(NPReason reason) { - if (id_ != 0) { - if (instance()->webplugin()) { - instance()->webplugin()->CancelResource(id_); - } - - id_ = 0; - } - + CancelRequest(); bool result = PluginStream::Close(reason); instance()->RemoveStream(this); return result; @@ -49,7 +43,6 @@ void PluginStreamUrl::DidReceiveResponse(const std::string& mime_type, uint32 expected_length, uint32 last_modified, bool* cancel) { - bool opened = Open(mime_type, headers, expected_length, @@ -60,21 +53,33 @@ void PluginStreamUrl::DidReceiveResponse(const std::string& mime_type, } } -void PluginStreamUrl::DidReceiveData(const char* buffer, int length) { +void PluginStreamUrl::DidReceiveData(const char* buffer, int length, + int data_offset) { if (!open()) return; if (length > 0) - Write(const_cast<char*>(buffer), length); + Write(const_cast<char*>(buffer), length, data_offset); } void PluginStreamUrl::DidFinishLoading() { - Close(NPRES_DONE); + if (!seekable()) { + Close(NPRES_DONE); + } } void PluginStreamUrl::DidFail() { Close(NPRES_NETWORK_ERR); } +void PluginStreamUrl::CancelRequest() { + if (id_ > 0) { + if (instance()->webplugin()) { + instance()->webplugin()->CancelResource(id_); + } + id_ = 0; + } +} + } // namespace NPAPI diff --git a/webkit/glue/plugins/plugin_stream_url.h b/webkit/glue/plugins/plugin_stream_url.h index ddffcd0..17213a2 100644 --- a/webkit/glue/plugins/plugin_stream_url.h +++ b/webkit/glue/plugins/plugin_stream_url.h @@ -34,6 +34,12 @@ class PluginStreamUrl : public PluginStream, // it is still loading. virtual bool Close(NPReason reason); + virtual WebPluginResourceClient* AsResourceClient() { + return static_cast<WebPluginResourceClient*>(this); + } + + virtual void CancelRequest(); + // // WebPluginResourceClient methods // @@ -43,10 +49,11 @@ class PluginStreamUrl : public PluginStream, uint32 expected_length, uint32 last_modified, bool* cancel); - void DidReceiveData(const char* buffer, int length); + void DidReceiveData(const char* buffer, int length, int data_offset); void DidFinishLoading(); void DidFail(); + private: GURL url_; int id_; diff --git a/webkit/glue/plugins/plugin_string_stream.cc b/webkit/glue/plugins/plugin_string_stream.cc index eea9a45..b1ad8d1 100644 --- a/webkit/glue/plugins/plugin_string_stream.cc +++ b/webkit/glue/plugins/plugin_string_stream.cc @@ -22,7 +22,7 @@ void PluginStringStream::SendToPlugin(const std::string &data, int length = static_cast<int>(data.length()); if (Open(mime_type, std::string(), length, 0)) { // TODO - check if it was not fully sent, and figure out a backup plan. - int written = Write(data.c_str(), length); + int written = Write(data.c_str(), length, 0); NPReason reason = written == length ? NPRES_DONE : NPRES_NETWORK_ERR; Close(reason); } diff --git a/webkit/glue/plugins/webplugin_delegate_impl.cc b/webkit/glue/plugins/webplugin_delegate_impl.cc index 7c7c47f..ab8dc17 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.cc +++ b/webkit/glue/plugins/webplugin_delegate_impl.cc @@ -1002,7 +1002,18 @@ WebCursor::Type WebPluginDelegateImpl::GetCursorType( WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( int resource_id, const std::string &url, bool notify_needed, - void *notify_data) { + void *notify_data, void* existing_stream) { + // Stream already exists. This typically happens for range requests + // initiated via NPN_RequestRead. + if (existing_stream) { + NPAPI::PluginStream* plugin_stream = + reinterpret_cast<NPAPI::PluginStream*>(existing_stream); + + plugin_stream->CancelRequest(); + + return plugin_stream->AsResourceClient(); + } + if (notify_needed) { instance()->SetURLLoadData(GURL(url.c_str()), notify_data); } diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index 623bf02..7d750ae 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -72,7 +72,8 @@ class WebPluginDelegateImpl : public WebPluginDelegate { virtual WebPluginResourceClient* CreateResourceClient(int resource_id, const std::string &url, bool notify_needed, - void *notify_data); + void *notify_data, + void* stream); virtual void URLRequestRouted(const std::string&url, bool notify_needed, void* notify_data); diff --git a/webkit/glue/webplugin.h b/webkit/glue/webplugin.h index df634e4..5cbf9a9 100644 --- a/webkit/glue/webplugin.h +++ b/webkit/glue/webplugin.h @@ -126,6 +126,16 @@ class WebPlugin { bool notify, const char* url, void* notify_data, bool popups_allowed) = 0; + // Cancels document load. + virtual void CancelDocumentLoad() = 0; + + // Initiates a HTTP range request. + virtual void InitiateHTTPRangeRequest(const char* url, + const char* range_info, + void* existing_stream, + bool notify_needed, + HANDLE notify_data) = 0; + private: DISALLOW_EVIL_CONSTRUCTORS(WebPlugin); }; @@ -140,7 +150,8 @@ class WebPluginResourceClient { uint32 expected_length, uint32 last_modified, bool* cancel) = 0; - virtual void DidReceiveData(const char* buffer, int length) = 0; + virtual void DidReceiveData(const char* buffer, int length, + int data_offset) = 0; virtual void DidFinishLoading() = 0; virtual void DidFail() = 0; }; diff --git a/webkit/glue/webplugin_delegate.h b/webkit/glue/webplugin_delegate.h index 33990b3..2300986 100644 --- a/webkit/glue/webplugin_delegate.h +++ b/webkit/glue/webplugin_delegate.h @@ -111,7 +111,8 @@ class WebPluginDelegate { virtual WebPluginResourceClient* CreateResourceClient(int resource_id, const std::string &url, bool notify_needed, - void *notify_data) = 0; + void *notify_data, + void* stream) = 0; // Notifies the delegate about a Get/Post URL request getting routed virtual void URLRequestRouted(const std::string&url, bool notify_needed, void* notify_data) = 0; diff --git a/webkit/glue/webplugin_impl.cc b/webkit/glue/webplugin_impl.cc index 0485e44..292b0e3 100644 --- a/webkit/glue/webplugin_impl.cc +++ b/webkit/glue/webplugin_impl.cc @@ -40,6 +40,7 @@ #include "base/sys_string_conversions.h" #include "net/base/escape.h" #include "webkit/glue/glue_util.h" +#include "webkit/glue/multipart_response_delegate.h" #include "webkit/glue/webkit_glue.h" #include "webkit/glue/webplugin_impl.h" #include "webkit/glue/plugins/plugin_host.h" @@ -48,6 +49,55 @@ #include "googleurl/src/gurl.h" #include "webkit/port/platform/cursor.h" +// This class handles invididual multipart responses. It is instantiated when +// we receive HTTP status code 206 in the HTTP response. This indicates +// that the response could have multiple parts each separated by a boundary +// specified in the response header. +class MultiPartResponseClient : public WebCore::ResourceHandleClient { + public: + MultiPartResponseClient(WebPluginResourceClient* resource_client) + : resource_client_(resource_client) { + Clear(); + } + + // Called when the multipart parser encounters an embedded multipart + // response. + virtual void didReceiveResponse(WebCore::ResourceHandle* handle, + const WebCore::ResourceResponse& response) { + if (!MultipartResponseDelegate::ReadContentRanges( + response, &byte_range_lower_bound_, &byte_range_upper_bound_)) { + NOTREACHED(); + return; + } + + resource_response_ = response; + } + + // Receives individual part data from a multipart response. + virtual void didReceiveData(WebCore::ResourceHandle* handle, + const char* data, int boundary_pos, + int length_received) { + int data_length = byte_range_upper_bound_ - byte_range_lower_bound_ + 1; + resource_client_->DidReceiveData( + data, data_length, byte_range_lower_bound_); + } + + void Clear() { + resource_response_ = WebCore::ResourceResponse(); + byte_range_lower_bound_ = 0; + byte_range_upper_bound_ = 0; + } + + private: + WebCore::ResourceResponse resource_response_; + // The lower bound of the byte range. + int byte_range_lower_bound_; + // The upper bound of the byte range. + int byte_range_upper_bound_; + // The handler for the data. + WebPluginResourceClient* resource_client_; +}; + WebPluginContainer::WebPluginContainer(WebPluginImpl* impl) : impl_(impl) { } WebPluginContainer::~WebPluginContainer() { @@ -799,6 +849,8 @@ std::wstring WebPluginImpl::GetAllHeaders( void WebPluginImpl::didReceiveResponse(WebCore::ResourceHandle* handle, const WebCore::ResourceResponse& response) { + static const int kHttpPartialResponseStatusCode = 206; + WebPluginResourceClient* client = GetClientFromHandle(handle); if (!client) return; @@ -807,6 +859,11 @@ void WebPluginImpl::didReceiveResponse(WebCore::ResourceHandle* handle, WebPluginContainer::ReadHttpResponseInfo(response, &http_response_info); bool cancel = false; + + if (response.httpStatusCode() == kHttpPartialResponseStatusCode) { + HandleHttpMultipartResponse(response, client); + return; + } client->DidReceiveResponse( base::SysWideToNativeMB(http_response_info.mime_type), @@ -846,14 +903,28 @@ void WebPluginImpl::didReceiveData(WebCore::ResourceHandle* handle, const char *buffer, int length, int) { WebPluginResourceClient* client = GetClientFromHandle(handle); - if (client) - client->DidReceiveData(buffer, length); + if (client) { + MultipartResponseDelegate* multi_part_handler = + multi_part_response_map_[client]; + if (multi_part_handler) { + multi_part_handler->OnReceivedData(buffer, length); + } else { + client->DidReceiveData(buffer, length, 0); + } + } } void WebPluginImpl::didFinishLoading(WebCore::ResourceHandle* handle) { WebPluginResourceClient* client = GetClientFromHandle(handle); - if (client) + if (client) { + MultiPartResponseHandlerMap::iterator index = + multi_part_response_map_.find(client); + if (index != multi_part_response_map_.end()) { + delete (*index).second; + multi_part_response_map_.erase(index); + } client->DidFinishLoading(); + } RemoveClient(handle); } @@ -980,7 +1051,7 @@ void WebPluginImpl::HandleURLRequest(const char *method, int resource_id = GetNextResourceId(); WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(resource_id, complete_url_string, - notify, notify_data); + notify, notify_data, NULL); // If the RouteToFrame call returned a failure then inform the result // back to the plugin asynchronously. @@ -991,7 +1062,7 @@ void WebPluginImpl::HandleURLRequest(const char *method, } InitiateHTTPRequest(resource_id, resource_client, method, buf, len, - GURL(complete_url_string)); + GURL(complete_url_string), NULL); } } @@ -1004,7 +1075,8 @@ bool WebPluginImpl::InitiateHTTPRequest(int resource_id, WebPluginResourceClient* client, const char* method, const char* buf, int buf_len, - const GURL& complete_url_string) { + const GURL& complete_url_string, + const char* range_info) { if (!client) { NOTREACHED(); return false; @@ -1019,6 +1091,9 @@ bool WebPluginImpl::InitiateHTTPRequest(int resource_id, info.request.setResourceType(ResourceType::OBJECT); info.request.setHTTPMethod(method); + if (range_info) + info.request.addHTTPHeaderField("Range", range_info); + const WebCore::String& referrer = frame()->loader()->outgoingReferrer(); if (!WebCore::FrameLoader::shouldHideReferrer( complete_url_string.spec().c_str(), referrer)) { @@ -1041,3 +1116,43 @@ bool WebPluginImpl::InitiateHTTPRequest(int resource_id, return true; } +void WebPluginImpl::CancelDocumentLoad() { + frame()->loader()->stopLoading(false); +} + +void WebPluginImpl::InitiateHTTPRangeRequest(const char* url, + const char* range_info, + HANDLE existing_stream, + bool notify_needed, + HANDLE notify_data) { + int resource_id = GetNextResourceId(); + std::string complete_url_string; + CompleteURL(url, &complete_url_string); + + WebPluginResourceClient* resource_client = + delegate_->CreateResourceClient(resource_id, complete_url_string, + notify_needed, notify_data, + existing_stream); + InitiateHTTPRequest(resource_id, resource_client, "GET", NULL, 0, + GURL(complete_url_string), range_info); +} + +void WebPluginImpl::HandleHttpMultipartResponse( + const WebCore::ResourceResponse& response, + WebPluginResourceClient* client) { + std::string multipart_boundary; + if (!MultipartResponseDelegate::ReadMultipartBoundary( + response, &multipart_boundary)) { + NOTREACHED(); + return; + } + + MultiPartResponseClient* multi_part_response_client = + new MultiPartResponseClient(client); + + MultipartResponseDelegate* multi_part_response_handler = + new MultipartResponseDelegate(multi_part_response_client, NULL, + response, + multipart_boundary); + multi_part_response_map_[client] = multi_part_response_handler; +} diff --git a/webkit/glue/webplugin_impl.h b/webkit/glue/webplugin_impl.h index 04b48b3..2a5efb5 100644 --- a/webkit/glue/webplugin_impl.h +++ b/webkit/glue/webplugin_impl.h @@ -6,6 +6,7 @@ #define WEBKIT_GLUE_WEBPLUGIN_IMPL_H__ #include <string> +#include <map> #include <vector> #include "config.h" @@ -25,6 +26,7 @@ class WebFrameImpl; class WebPluginDelegate; class WebPluginImpl; +class MultipartResponseDelegate; namespace WebCore { class DeprecatedString; @@ -149,7 +151,8 @@ class WebPluginImpl : public WebPlugin, // Returns true on success. bool InitiateHTTPRequest(int resource_id, WebPluginResourceClient* client, const char* method, const char* buf, int buf_len, - const GURL& complete_url_string); + const GURL& complete_url_string, + const char* range_info); gfx::Rect GetWindowClipRect(const gfx::Rect& rect); @@ -242,6 +245,17 @@ class WebPluginImpl : public WebPlugin, bool notify, const char* url, void* notify_data, bool popups_allowed); + void CancelDocumentLoad(); + + void InitiateHTTPRangeRequest(const char* url, const char* range_info, + HANDLE existing_stream, bool notify_needed, + HANDLE notify_data); + + // Handles HTTP multipart responses, i.e. responses received with a HTTP + // status code of 206. + void HandleHttpMultipartResponse(const WebCore::ResourceResponse& response, + WebPluginResourceClient* client); + struct ClientInfo { int id; WebPluginResourceClient* client; @@ -264,6 +278,12 @@ class WebPluginImpl : public WebPlugin, WebPluginContainer* widget_; + typedef std::map<WebPluginResourceClient*, MultipartResponseDelegate*> + MultiPartResponseHandlerMap; + // Tracks HTTP multipart response handlers instantiated for + // a WebPluginResourceClient instance. + MultiPartResponseHandlerMap multi_part_response_map_; + DISALLOW_EVIL_CONSTRUCTORS(WebPluginImpl); }; |