summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/common/plugin_messages.h7
-rw-r--r--chrome/common/plugin_messages_internal.h13
-rw-r--r--chrome/plugin/webplugin_delegate_stub.cc9
-rw-r--r--chrome/plugin/webplugin_delegate_stub.h3
-rw-r--r--chrome/plugin/webplugin_proxy.cc14
-rw-r--r--chrome/plugin/webplugin_proxy.h7
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.cc27
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.h8
-rw-r--r--webkit/build/glue/glue.vcproj8
-rw-r--r--webkit/glue/SConscript1
-rw-r--r--webkit/glue/multipart_response_delegate.cc80
-rw-r--r--webkit/glue/multipart_response_delegate.h13
-rw-r--r--webkit/glue/multipart_response_delegate_unittest.cc89
-rw-r--r--webkit/glue/plugins/plugin_data_stream.cc46
-rw-r--r--webkit/glue/plugins/plugin_data_stream.h42
-rw-r--r--webkit/glue/plugins/plugin_host.cc17
-rw-r--r--webkit/glue/plugins/plugin_instance.cc79
-rw-r--r--webkit/glue/plugins/plugin_instance.h5
-rw-r--r--webkit/glue/plugins/plugin_stream.cc55
-rw-r--r--webkit/glue/plugins/plugin_stream.h32
-rw-r--r--webkit/glue/plugins/plugin_stream_url.cc29
-rw-r--r--webkit/glue/plugins/plugin_stream_url.h9
-rw-r--r--webkit/glue/plugins/plugin_string_stream.cc2
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.cc13
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h3
-rw-r--r--webkit/glue/webplugin.h13
-rw-r--r--webkit/glue/webplugin_delegate.h3
-rw-r--r--webkit/glue/webplugin_impl.cc127
-rw-r--r--webkit/glue/webplugin_impl.h22
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);
};