summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-04 06:43:35 +0000
committerananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-04 06:43:35 +0000
commit4736610c8c5210c61efbf985b7e56843c7cfa219 (patch)
tree0842657b27f9055b6653708e9025ee6ff076f2ea
parentb9e8ea61b8b7b897292bfc69814444dd9e938477 (diff)
downloadchromium_src-4736610c8c5210c61efbf985b7e56843c7cfa219.zip
chromium_src-4736610c8c5210c61efbf985b7e56843c7cfa219.tar.gz
chromium_src-4736610c8c5210c61efbf985b7e56843c7cfa219.tar.bz2
Revert 76880 - ChromeFrame would fail to upload POST data to the server if the webserver requested NTLM
authentication. This is due to a bug in urlmon on IE6 and IE7 which manifests itself when the post data is passed to urlmon as an IStream. Fix is to pass in the uploaded data as a HGLOBAL. We always pass in a copy of the HGLOBAL which points to the posted data to urlmon. This is to have it accessible for reissuing navigation requests which target downloads. Fixes bug http://code.google.com/p/chromium/issues/detail?id=62687 BUG=62687 TEST=manually at this point. As we need a server which supports NTLM authentication like IIS. Review URL: http://codereview.chromium.org/6603006 TBR=ananta@chromium.org Review URL: http://codereview.chromium.org/6626008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76886 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome_frame/chrome_frame.gyp4
-rw-r--r--chrome_frame/chrome_frame_activex_base.h3
-rw-r--r--chrome_frame/npapi_url_request.cc10
-rw-r--r--chrome_frame/plugin_url_request.cc34
-rw-r--r--chrome_frame/plugin_url_request.h17
-rw-r--r--chrome_frame/urlmon_moniker.cc2
-rw-r--r--chrome_frame/urlmon_upload_data_stream.cc100
-rw-r--r--chrome_frame/urlmon_upload_data_stream.h41
-rw-r--r--chrome_frame/urlmon_upload_data_stream_unittest.cc162
-rw-r--r--chrome_frame/urlmon_url_request.cc54
-rw-r--r--chrome_frame/urlmon_url_request.h3
-rw-r--r--chrome_frame/urlmon_url_request_private.h2
-rw-r--r--chrome_frame/utils.cc39
-rw-r--r--chrome_frame/utils.h13
14 files changed, 401 insertions, 83 deletions
diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp
index 3992e11..273ae7c 100644
--- a/chrome_frame/chrome_frame.gyp
+++ b/chrome_frame/chrome_frame.gyp
@@ -147,6 +147,8 @@
'test/win_event_receiver.cc',
'unittest_precompile.h',
'unittest_precompile.cc',
+ 'urlmon_upload_data_stream.cc',
+ 'urlmon_upload_data_stream_unittest.cc',
'vtable_patch_manager_unittest.cc',
],
'include_dirs': [
@@ -848,6 +850,8 @@
'urlmon_url_request.cc',
'urlmon_url_request.h',
'urlmon_url_request_private.h',
+ 'urlmon_upload_data_stream.cc',
+ 'urlmon_upload_data_stream.h',
'utils.h',
'utils.cc',
'vtable_patch_manager.cc',
diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h
index 0472906..b80caf1 100644
--- a/chrome_frame/chrome_frame_activex_base.h
+++ b/chrome_frame/chrome_frame_activex_base.h
@@ -475,8 +475,7 @@ END_MSG_MAP()
NavigateBrowserToMoniker(
doc_site_, download_params->moniker,
UTF8ToWide(download_params->request_headers).c_str(),
- download_params->bind_ctx, NULL, download_params->post_data,
- download_params->post_data_len);
+ download_params->bind_ctx, NULL, download_params->post_data);
}
return TRUE;
}
diff --git a/chrome_frame/npapi_url_request.cc b/chrome_frame/npapi_url_request.cc
index 885c390..ac091df 100644
--- a/chrome_frame/npapi_url_request.cc
+++ b/chrome_frame/npapi_url_request.cc
@@ -91,8 +91,14 @@ bool NPAPIUrlRequest::Start() {
buffer += base::IntToString(data_len);
buffer += "\r\n\r\n";
}
- buffer.append(reinterpret_cast<char*>(&upload_data_[0]),
- upload_data_.size());
+
+ std::string data;
+ data.resize(data_len);
+ uint32 bytes_read;
+ upload_data_->Read(&data[0], data_len,
+ reinterpret_cast<ULONG*>(&bytes_read));
+ DCHECK_EQ(data_len, bytes_read);
+ buffer += data;
result = npapi::PostURLNotify(instance_, url().c_str(), NULL,
buffer.length(), buffer.c_str(), false, this);
diff --git a/chrome_frame/plugin_url_request.cc b/chrome_frame/plugin_url_request.cc
index 8af3e1e..e0166bc 100644
--- a/chrome_frame/plugin_url_request.cc
+++ b/chrome_frame/plugin_url_request.cc
@@ -14,8 +14,7 @@ PluginUrlRequest::PluginUrlRequest()
enable_frame_busting_(false),
resource_type_(ResourceType::MAIN_FRAME),
load_flags_(0),
- is_chunked_upload_(false),
- upload_data_(NULL) {
+ is_chunked_upload_(false) {
}
PluginUrlRequest::~PluginUrlRequest() {
@@ -35,22 +34,25 @@ bool PluginUrlRequest::Initialize(PluginUrlRequestDelegate* delegate,
resource_type_ = resource_type;
load_flags_ = load_flags;
- if (upload_data && upload_data->GetContentLength()) {
- post_data_len_ = upload_data->GetContentLength();
- is_chunked_upload_ = upload_data->is_chunked();
-
-#pragma warning(disable:4244)
- upload_data_.reserve(post_data_len_);
-#pragma warning(default:4244)
-
- std::vector<net::UploadData::Element>::iterator element_index;
- for (element_index = upload_data->elements()->begin();
- element_index != upload_data->elements()->end();
- ++element_index) {
- std::copy(element_index->bytes().begin(), element_index->bytes().end(),
- std::back_inserter(upload_data_));
+ if (upload_data) {
+ // We store a pointer to UrlmonUploadDataStream and not net::UploadData
+ // since UrlmonUploadDataStream implements thread safe ref counting and
+ // UploadData does not.
+ CComObject<UrlmonUploadDataStream>* upload_stream = NULL;
+ HRESULT hr = CComObject<UrlmonUploadDataStream>::CreateInstance(
+ &upload_stream);
+ if (FAILED(hr)) {
+ NOTREACHED();
+ } else {
+ post_data_len_ = upload_data->GetContentLength();
+ upload_stream->AddRef();
+ upload_stream->Initialize(upload_data);
+ upload_data_.Attach(upload_stream);
+ is_chunked_upload_ = upload_data->is_chunked();
}
}
+
enable_frame_busting_ = enable_frame_busting;
+
return true;
}
diff --git a/chrome_frame/plugin_url_request.h b/chrome_frame/plugin_url_request.h
index 7afa25b..57a30c6 100644
--- a/chrome_frame/plugin_url_request.h
+++ b/chrome_frame/plugin_url_request.h
@@ -12,6 +12,7 @@
#include "base/scoped_comptr_win.h"
#include "base/time.h"
#include "chrome_frame/chrome_frame_delegate.h"
+#include "chrome_frame/urlmon_upload_data_stream.h"
#include "ipc/ipc_message.h"
#include "net/base/host_port_pair.h"
#include "net/base/upload_data.h"
@@ -155,10 +156,24 @@ class PluginUrlRequest {
}
protected:
+ HRESULT get_upload_data(IStream** ret) {
+ DCHECK(ret);
+ if (!upload_data_.get())
+ return S_FALSE;
+ *ret = upload_data_.get();
+ (*ret)->AddRef();
+ return S_OK;
+ }
+
void set_url(const std::string& url) {
url_ = url;
}
+ void ClearPostData() {
+ upload_data_.Release();
+ post_data_len_ = 0;
+ }
+
void SendData();
bool enable_frame_busting_;
@@ -171,7 +186,7 @@ class PluginUrlRequest {
std::string extra_headers_;
ResourceType::Type resource_type_;
int load_flags_;
- std::vector<uint8> upload_data_;
+ ScopedComPtr<IStream> upload_data_;
bool is_chunked_upload_;
// Contains the ip address and port of the destination host.
net::HostPortPair socket_address_;
diff --git a/chrome_frame/urlmon_moniker.cc b/chrome_frame/urlmon_moniker.cc
index 33cbdc5..b7cc23d 100644
--- a/chrome_frame/urlmon_moniker.cc
+++ b/chrome_frame/urlmon_moniker.cc
@@ -63,7 +63,7 @@ HRESULT NavigationManager::NavigateToCurrentUrlInCF(IBrowserService* browser) {
}
hr = NavigateBrowserToMoniker(browser, moniker, headers.c_str(),
- bind_context, fragment.c_str(), NULL, 0);
+ bind_context, fragment.c_str(), NULL);
DVLOG(1) << base::StringPrintf("NavigateBrowserToMoniker: 0x%08X", hr);
}
}
diff --git a/chrome_frame/urlmon_upload_data_stream.cc b/chrome_frame/urlmon_upload_data_stream.cc
new file mode 100644
index 0000000..5664fbf
--- /dev/null
+++ b/chrome_frame/urlmon_upload_data_stream.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2009 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 "chrome_frame/urlmon_upload_data_stream.h"
+
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+void UrlmonUploadDataStream::Initialize(net::UploadData* upload_data) {
+ upload_data_ = upload_data;
+ request_body_stream_.reset(net::UploadDataStream::Create(upload_data, NULL));
+ DCHECK(request_body_stream_.get());
+}
+
+STDMETHODIMP UrlmonUploadDataStream::Read(void* pv, ULONG cb, ULONG* read) {
+ if (pv == NULL) {
+ NOTREACHED();
+ return E_POINTER;
+ }
+
+ // Have we already read past the end of the stream?
+ if (request_body_stream_->eof()) {
+ if (read) {
+ *read = 0;
+ }
+ return S_FALSE;
+ }
+
+ uint64 total_bytes_to_copy = std::min(static_cast<uint64>(cb),
+ static_cast<uint64>(request_body_stream_->buf_len()));
+
+ uint64 bytes_copied = 0;
+
+ char* write_pointer = reinterpret_cast<char*>(pv);
+ while (bytes_copied < total_bytes_to_copy) {
+ net::IOBuffer* buf = request_body_stream_->buf();
+
+ // Make sure our length doesn't run past the end of the available data.
+ size_t bytes_to_copy_now = static_cast<size_t>(
+ std::min(static_cast<uint64>(request_body_stream_->buf_len()),
+ total_bytes_to_copy - bytes_copied));
+
+ memcpy(write_pointer, buf->data(), bytes_to_copy_now);
+
+ // Advance our copy tally
+ bytes_copied += bytes_to_copy_now;
+
+ // Advance our write pointer
+ write_pointer += bytes_to_copy_now;
+
+ // Advance the UploadDataStream read pointer:
+ request_body_stream_->MarkConsumedAndFillBuffer(bytes_to_copy_now);
+ }
+
+ DCHECK(bytes_copied == total_bytes_to_copy);
+
+ if (read) {
+ *read = static_cast<ULONG>(total_bytes_to_copy);
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP UrlmonUploadDataStream::Seek(LARGE_INTEGER move, DWORD origin,
+ ULARGE_INTEGER* new_pos) {
+ // UploadDataStream is really not very seek-able, so for now allow
+ // STREAM_SEEK_SETs to work with a 0 offset, but fail on everything else.
+ if (origin == STREAM_SEEK_SET && move.QuadPart == 0) {
+ if (request_body_stream_->position() != 0) {
+ request_body_stream_.reset(
+ net::UploadDataStream::Create(upload_data_, NULL));
+ DCHECK(request_body_stream_.get());
+ }
+ if (new_pos) {
+ new_pos->QuadPart = 0;
+ }
+ return S_OK;
+ }
+
+ DCHECK(false) << __FUNCTION__;
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP UrlmonUploadDataStream::Stat(STATSTG *stat_stg,
+ DWORD grf_stat_flag) {
+ if (stat_stg == NULL)
+ return E_POINTER;
+
+ memset(stat_stg, 0, sizeof(STATSTG));
+ if (0 == (grf_stat_flag & STATFLAG_NONAME)) {
+ const wchar_t kStreamBuffer[] = L"PostStream";
+ stat_stg->pwcsName =
+ static_cast<wchar_t*>(::CoTaskMemAlloc(sizeof(kStreamBuffer)));
+ lstrcpy(stat_stg->pwcsName, kStreamBuffer);
+ }
+ stat_stg->type = STGTY_STREAM;
+ stat_stg->cbSize.QuadPart = upload_data_->GetContentLength();
+ return S_OK;
+}
diff --git a/chrome_frame/urlmon_upload_data_stream.h b/chrome_frame/urlmon_upload_data_stream.h
new file mode 100644
index 0000000..8f715ed
--- /dev/null
+++ b/chrome_frame/urlmon_upload_data_stream.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2010 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 CHROME_FRAME_URLMON_UPLOAD_DATA_STREAM_H_
+#define CHROME_FRAME_URLMON_UPLOAD_DATA_STREAM_H_
+
+#include <urlmon.h>
+#include <atlbase.h>
+#include <atlcom.h>
+
+#include "base/ref_counted.h"
+#include "chrome_frame/stream_impl.h"
+#include "net/base/upload_data.h"
+#include "net/base/upload_data_stream.h"
+
+// Provides an IStream interface to the very different UploadDataStream
+// implementation.
+class UrlmonUploadDataStream : public CComObjectRootEx<CComMultiThreadModel>,
+ public StreamImpl {
+ public:
+ UrlmonUploadDataStream() {}
+
+ BEGIN_COM_MAP(UrlmonUploadDataStream)
+ COM_INTERFACE_ENTRY(ISequentialStream)
+ COM_INTERFACE_ENTRY(IStream)
+ END_COM_MAP()
+
+ void Initialize(net::UploadData* upload_data);
+
+ // Partial implementation of IStream.
+ STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read);
+ STDMETHOD(Seek)(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER* new_pos);
+ STDMETHOD(Stat)(STATSTG *pstatstg, DWORD grfStatFlag);
+
+ private:
+ scoped_refptr<net::UploadData> upload_data_;
+ scoped_ptr<net::UploadDataStream> request_body_stream_;
+};
+
+#endif // CHROME_FRAME_URLMON_UPLOAD_DATA_STREAM_H_
diff --git a/chrome_frame/urlmon_upload_data_stream_unittest.cc b/chrome_frame/urlmon_upload_data_stream_unittest.cc
new file mode 100644
index 0000000..a34ba2c
--- /dev/null
+++ b/chrome_frame/urlmon_upload_data_stream_unittest.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2009 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 "gtest/gtest.h"
+
+#include "base/ref_counted.h"
+#include "base/scoped_comptr_win.h"
+#include "chrome_frame/urlmon_upload_data_stream.h"
+
+TEST(UrlmonUploadDataStreamTest, TestBasicRead) {
+ char random_string[] = "some random data, no really this totally random";
+ int random_string_length = strlen(random_string);
+ scoped_refptr<net::UploadData> upload_data = new net::UploadData();
+ upload_data->AppendBytes(random_string, random_string_length);
+
+ CComObject<UrlmonUploadDataStream>* upload_stream = NULL;
+ HRESULT hr =
+ CComObject<UrlmonUploadDataStream>::CreateInstance(&upload_stream);
+ ASSERT_TRUE(SUCCEEDED(hr));
+
+ upload_stream->Initialize(upload_data.get());
+ ScopedComPtr<IStream> upload_istream(upload_stream);
+
+ char buffer[500];
+ memset(buffer, 0, 500);
+ ULONG bytes_read = 0;
+ hr = upload_istream->Read(buffer, 500, &bytes_read);
+
+ EXPECT_TRUE(SUCCEEDED(hr));
+ EXPECT_EQ(bytes_read, random_string_length);
+ EXPECT_TRUE(strcmp(buffer, random_string) == 0);
+
+ char buffer2[500];
+ memset(buffer2, 0, 500);
+ ULONG bytes_read2 = 0;
+ hr = upload_istream->Read(buffer2, 500, &bytes_read2);
+
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(bytes_read2, 0);
+ EXPECT_FALSE(strcmp(buffer2, random_string) == 0);
+}
+
+TEST(UrlmonUploadDataStreamTest, TestBigRead) {
+ const size_t kBigBufferLength = 100000;
+ char big_buffer[kBigBufferLength];
+ memset(big_buffer, 'a', kBigBufferLength);
+
+ scoped_refptr<net::UploadData> upload_data = new net::UploadData();
+ upload_data->AppendBytes(big_buffer, kBigBufferLength);
+
+ CComObject<UrlmonUploadDataStream>* upload_stream = NULL;
+ HRESULT hr =
+ CComObject<UrlmonUploadDataStream>::CreateInstance(&upload_stream);
+ ASSERT_TRUE(SUCCEEDED(hr));
+
+ upload_stream->Initialize(upload_data.get());
+ ScopedComPtr<IStream> upload_istream(upload_stream);
+
+ char big_rcv_buffer[kBigBufferLength];
+ int write_pos = 0;
+ ULONG bytes_read = 0;
+ hr = E_UNEXPECTED;
+
+ while ((hr = upload_istream->Read(&big_rcv_buffer[write_pos],
+ kBigBufferLength,
+ &bytes_read)) != S_FALSE) {
+ EXPECT_TRUE(SUCCEEDED(hr));
+ EXPECT_GT(bytes_read, static_cast<ULONG>(0));
+
+ write_pos += bytes_read;
+ bytes_read = 0;
+ }
+
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_TRUE((write_pos + bytes_read) == kBigBufferLength);
+ EXPECT_EQ(0, memcmp(big_buffer, big_rcv_buffer, kBigBufferLength));
+}
+
+TEST(UrlmonUploadDataStreamTest, TestStat) {
+ char random_string[] = "some random data, no really this totally random";
+ int random_string_length = strlen(random_string);
+ scoped_refptr<net::UploadData> upload_data = new net::UploadData();
+ upload_data->AppendBytes(random_string, random_string_length);
+
+ CComObject<UrlmonUploadDataStream>* upload_stream = NULL;
+ HRESULT hr =
+ CComObject<UrlmonUploadDataStream>::CreateInstance(&upload_stream);
+ ASSERT_TRUE(SUCCEEDED(hr));
+
+ upload_stream->Initialize(upload_data.get());
+ ScopedComPtr<IStream> upload_istream(upload_stream);
+
+ STATSTG statstg;
+ hr = upload_stream->Stat(&statstg, STATFLAG_NONAME);
+ EXPECT_TRUE(SUCCEEDED(hr));
+ EXPECT_EQ(static_cast<LONGLONG>(random_string_length),
+ statstg.cbSize.QuadPart);
+}
+
+TEST(UrlmonUploadDataStreamTest, TestRepeatedRead) {
+ char random_string[] = "some random data, no really this totally random";
+ int random_string_length = strlen(random_string);
+ scoped_refptr<net::UploadData> upload_data = new net::UploadData();
+ upload_data->AppendBytes(random_string, random_string_length);
+
+ CComObject<UrlmonUploadDataStream>* upload_stream = NULL;
+ HRESULT hr =
+ CComObject<UrlmonUploadDataStream>::CreateInstance(&upload_stream);
+ ASSERT_TRUE(SUCCEEDED(hr));
+
+ upload_stream->Initialize(upload_data.get());
+ ScopedComPtr<IStream> upload_istream(upload_stream);
+
+ char buffer[500];
+ memset(buffer, 0, 500);
+ ULONG bytes_read = 0;
+ hr = upload_istream->Read(buffer, 500, &bytes_read);
+
+ EXPECT_TRUE(SUCCEEDED(hr));
+ EXPECT_EQ(bytes_read, random_string_length);
+ EXPECT_EQ(0, strcmp(buffer, random_string));
+
+ char buffer2[500];
+ memset(buffer2, 0, 500);
+ ULONG bytes_read2 = 0;
+
+ for (int i = 0; i < 10; i++) {
+ hr = upload_istream->Read(buffer2, 500, &bytes_read2);
+ EXPECT_EQ(S_FALSE, hr);
+ EXPECT_EQ(bytes_read2, 0);
+ EXPECT_NE(0, strcmp(buffer2, random_string));
+ }
+}
+
+TEST(UrlmonUploadDataStreamTest, TestZeroRead) {
+ char random_string[] = "some random data, no really this totally random";
+ int random_string_length = strlen(random_string);
+ scoped_refptr<net::UploadData> upload_data = new net::UploadData();
+ upload_data->AppendBytes(random_string, random_string_length);
+
+ CComObject<UrlmonUploadDataStream>* upload_stream = NULL;
+ HRESULT hr =
+ CComObject<UrlmonUploadDataStream>::CreateInstance(&upload_stream);
+ ASSERT_TRUE(SUCCEEDED(hr));
+
+ upload_stream->Initialize(upload_data.get());
+ ScopedComPtr<IStream> upload_istream(upload_stream);
+
+ char buffer[500];
+ memset(buffer, 0, 500);
+ ULONG bytes_read = 42;
+ hr = upload_istream->Read(&buffer[0], 0, &bytes_read);
+
+ EXPECT_EQ(S_OK, hr);
+ EXPECT_EQ(0, bytes_read);
+
+ char buffer2[500];
+ memset(&buffer2[0], 0, 500);
+ EXPECT_EQ(0, memcmp(buffer, buffer2, 500));
+}
+
diff --git a/chrome_frame/urlmon_url_request.cc b/chrome_frame/urlmon_url_request.cc
index a6bf1e6..81a3d88 100644
--- a/chrome_frame/urlmon_url_request.cc
+++ b/chrome_frame/urlmon_url_request.cc
@@ -19,6 +19,7 @@
#include "chrome_frame/extra_system_apis.h"
#include "chrome_frame/html_utils.h"
#include "chrome_frame/urlmon_url_request_private.h"
+#include "chrome_frame/urlmon_upload_data_stream.h"
#include "chrome_frame/utils.h"
#include "chrome/common/automation_messages.h"
#include "net/base/load_flags.h"
@@ -165,20 +166,8 @@ void UrlmonUrlRequest::TerminateBind(TerminateBindCallback* callback) {
DVLOG(1) << __FUNCTION__ << me();
cleanup_transaction_ = false;
if (status_.get_state() == Status::DONE) {
- // We may receive a top level POST with no data. We stil need to reissue
- // the navigation as a POST request. To achieve this we add a dummy value
- // to the data being uploaded.
- // May not work as expected with some web sites.
- if (upload_data_.size() == 0 && LowerCaseEqualsASCII(method(), "post")) {
- DLOG(WARNING) << "Reissuing navigation with empty POST data. May not"
- << " work as expected";
- upload_data_.push_back(0);
- }
// Binding is stopped. Note result could be an error.
- callback->Run(moniker_,
- bind_context_,
- (upload_data_.size() > 0 ? &upload_data_[0] : NULL),
- upload_data_.size(),
+ callback->Run(moniker_, bind_context_, upload_data_,
request_headers_.c_str());
delete callback;
} else {
@@ -379,21 +368,8 @@ STDMETHODIMP UrlmonUrlRequest::OnStopBinding(HRESULT result, LPCWSTR error) {
if (result == INET_E_TERMINATED_BIND) {
if (terminate_requested()) {
- // We may receive a top level POST with no data. We stil need to reissue
- // the navigation as a POST request. To achieve this we add a dummy value
- // to the data being uploaded.
- // May not work as expected with some web sites.
- if (upload_data_.size() == 0 && LowerCaseEqualsASCII(method(), "post")) {
- DLOG(WARNING) << "Reissuing navigation with empty POST data. May not"
- << " work as expected";
- upload_data_.push_back(0);
- }
- terminate_bind_callback_->Run(
- moniker_,
- bind_context_,
- (upload_data_.size() > 0 ? &upload_data_[0] : NULL),
- upload_data_.size(),
- request_headers_.c_str());
+ terminate_bind_callback_->Run(moniker_, bind_context_, upload_data_,
+ request_headers_.c_str());
} else {
cleanup_transaction_ = true;
}
@@ -506,16 +482,16 @@ STDMETHODIMP UrlmonUrlRequest::GetBindInfo(DWORD* bind_flags,
if (bind_info->dwBindVerb != BINDVERB_CUSTOM)
bind_info->szCustomVerb = NULL;
- bind_info->stgmedData.tymed = TYMED_HGLOBAL;
-#pragma warning(disable:4244)
- bind_info->stgmedData.hGlobal = ::GlobalAlloc(GMEM_FIXED, post_data_len());
- memcpy(bind_info->stgmedData.hGlobal, &upload_data_[0], post_data_len());
- bind_info->cbstgmedData = post_data_len();
-#pragma warning(default:4244)
- DVLOG(1) << __FUNCTION__ << me() << method()
- << " request with " << base::Int64ToString(post_data_len())
- << " bytes. url=" << url();
+ if (get_upload_data(&bind_info->stgmedData.pstm) == S_OK) {
+ bind_info->stgmedData.tymed = TYMED_ISTREAM;
+ DVLOG(1) << __FUNCTION__ << me() << method()
+ << " request with " << base::Int64ToString(post_data_len())
+ << " bytes. url=" << url();
+ } else {
+ DVLOG(1) << __FUNCTION__ << me() << "POST request with no data!";
+ }
}
+
return S_OK;
}
@@ -1098,14 +1074,12 @@ void UrlmonUrlRequestManager::DownloadRequestInHost(int request_id) {
void UrlmonUrlRequestManager::BindTerminated(IMoniker* moniker,
IBindCtx* bind_ctx,
- uint8* post_data,
- int post_data_len,
+ IStream* post_data,
const char* request_headers) {
DownloadInHostParams download_params;
download_params.bind_ctx = bind_ctx;
download_params.moniker = moniker;
download_params.post_data = post_data;
- download_params.post_data_len = post_data_len;
if (request_headers) {
download_params.request_headers = request_headers;
}
diff --git a/chrome_frame/urlmon_url_request.h b/chrome_frame/urlmon_url_request.h
index e9d7bef..496c33d 100644
--- a/chrome_frame/urlmon_url_request.h
+++ b/chrome_frame/urlmon_url_request.h
@@ -107,8 +107,7 @@ class UrlmonUrlRequestManager
// We simply forward moniker and bind_ctx to host ActiveX/ActiveDocument,
// so it may start NavigateWithBindContext.
void BindTerminated(IMoniker* moniker, IBindCtx* bind_ctx,
- uint8* post_data, int post_data_len,
- const char* request_headers);
+ IStream* post_data, const char* request_headers);
// Map for (request_id <-> UrlmonUrlRequest)
typedef std::map<int, scoped_refptr<UrlmonUrlRequest> > RequestMap;
diff --git a/chrome_frame/urlmon_url_request_private.h b/chrome_frame/urlmon_url_request_private.h
index f4cae5c..60ca118 100644
--- a/chrome_frame/urlmon_url_request_private.h
+++ b/chrome_frame/urlmon_url_request_private.h
@@ -39,7 +39,7 @@ class UrlmonUrlRequest
// Used from "DownloadRequestInHost".
// Callback will be invoked either right away (if operation is finished) or
// from inside ::OnStopBinding() when it is safe to reuse the bind_context.
- typedef Callback5<IMoniker*, IBindCtx*, uint8*, int, const char*>::Type
+ typedef Callback4<IMoniker*, IBindCtx*, IStream*, const char*>::Type
TerminateBindCallback;
void TerminateBind(TerminateBindCallback* callback);
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index f622c7d..1db94dc 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -791,13 +791,9 @@ RendererType RendererTypeForUrl(const std::wstring& url) {
return renderer_type;
}
-HRESULT NavigateBrowserToMoniker(IUnknown* browser,
- IMoniker* moniker,
- const wchar_t* headers,
- IBindCtx* bind_ctx,
- const wchar_t* fragment,
- const uint8* post_data,
- int post_data_len) {
+HRESULT NavigateBrowserToMoniker(IUnknown* browser, IMoniker* moniker,
+ const wchar_t* headers, IBindCtx* bind_ctx,
+ const wchar_t* fragment, IStream* post_data) {
DCHECK(browser);
DCHECK(moniker);
DCHECK(bind_ctx);
@@ -821,9 +817,34 @@ HRESULT NavigateBrowserToMoniker(IUnknown* browser,
// If the data to be downloaded was received in response to a post request
// then we need to reissue the post request.
base::win::ScopedVariant post_data_variant;
- if (post_data && post_data_len > 0) {
+ if (post_data) {
+ RewindStream(post_data);
+
CComSafeArray<uint8> safe_array_post;
- safe_array_post.Add(post_data_len, post_data);
+
+ STATSTG stat;
+ post_data->Stat(&stat, STATFLAG_NONAME);
+
+ if (stat.cbSize.LowPart > 0) {
+ std::string data;
+
+ HRESULT hr = E_FAIL;
+ while ((hr = ReadStream(post_data, 0xffff, &data)) == S_OK) {
+ safe_array_post.Add(
+ data.size(),
+ reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())));
+ data.clear();
+ }
+ } else {
+ // If we get here it means that the navigation is being reissued for a
+ // POST request with no data. To ensure that the new window used as a
+ // target to handle the new navigation issues a POST request
+ // we need valid POST data. In this case we create a dummy 1 byte array.
+ // May not work as expected with some web sites.
+ DLOG(WARNING) << "Reissuing navigation with empty POST data. May not"
+ << " work as expected";
+ safe_array_post.Create(1);
+ }
post_data_variant.Set(safe_array_post.Detach());
}
// Create a new bind context that's not associated with our callback.
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index ca5cb87..c2d6ef9 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -301,13 +301,9 @@ HRESULT DoQueryService(const IID& service_id, IUnknown* unk, T** service) {
// Navigates an IWebBrowser2 object to a moniker.
// |headers| can be NULL.
-HRESULT NavigateBrowserToMoniker(IUnknown* browser,
- IMoniker* moniker,
- const wchar_t* headers,
- IBindCtx* bind_ctx,
- const wchar_t* fragment,
- const uint8* post_data,
- int post_data_len);
+HRESULT NavigateBrowserToMoniker(IUnknown* browser, IMoniker* moniker,
+ const wchar_t* headers, IBindCtx* bind_ctx,
+ const wchar_t* fragment, IStream* post_data);
// Raises a flag on the current thread (using TLS) to indicate that an
// in-progress navigation should be rendered in chrome frame.
@@ -467,8 +463,7 @@ extern base::Lock g_ChromeFrameHistogramLock;
struct DownloadInHostParams {
IBindCtx* bind_ctx;
IMoniker* moniker;
- uint8* post_data;
- int post_data_len;
+ IStream* post_data;
std::string request_headers;
};