summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoriyengar@google.com <iyengar@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-19 02:09:49 +0000
committeriyengar@google.com <iyengar@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-19 02:09:49 +0000
commit84f89cacc8f09a2fbc1fd82b30af13dd35624869 (patch)
tree9e60daee9caffaaaa3da96fd46b0c4ba28318fc8
parent172300b0cd0748cade220e03dcc2b3459ee14b80 (diff)
downloadchromium_src-84f89cacc8f09a2fbc1fd82b30af13dd35624869.zip
chromium_src-84f89cacc8f09a2fbc1fd82b30af13dd35624869.tar.gz
chromium_src-84f89cacc8f09a2fbc1fd82b30af13dd35624869.tar.bz2
This CB fixes the following issue1. http://code.google.com/p/chromium/issues/detail?id=206This is a performance issue while loading PDF documents. The fix is to support PDF fast webview, which is basically support for the NPN_RequestRead API, which allows a plugin to request specific byte ranges in HTTP GET requests. This also needs support for seekable streams. Our support for seekable streams is limited to HTTP servers which allow byte range requests. Firefox also supports a mode in which the the browser caches the file on disk for servers which don't support byte range requests. The plugin_data_stream.cc/.h files are being removed as there is not much value in their existence. The needed functionality is available in the PluginStreamUrl class, which now services manual data streams as well. Testing this is a touch tricky as we need a HTTP server which serves byte range requests. Will add those in a subsequent CB.Also fixed a bug in the multipart parser where we need to ignore leading newline characters while parsing the header.Bug=206
Review URL: http://codereview.chromium.org/2896 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2400 0039d316-1c4b-4281-b951-d872f2087c98
-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);
};