diff options
author | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-04 06:43:35 +0000 |
---|---|---|
committer | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-04 06:43:35 +0000 |
commit | 4736610c8c5210c61efbf985b7e56843c7cfa219 (patch) | |
tree | 0842657b27f9055b6653708e9025ee6ff076f2ea /chrome_frame | |
parent | b9e8ea61b8b7b897292bfc69814444dd9e938477 (diff) | |
download | chromium_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
Diffstat (limited to 'chrome_frame')
-rw-r--r-- | chrome_frame/chrome_frame.gyp | 4 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_activex_base.h | 3 | ||||
-rw-r--r-- | chrome_frame/npapi_url_request.cc | 10 | ||||
-rw-r--r-- | chrome_frame/plugin_url_request.cc | 34 | ||||
-rw-r--r-- | chrome_frame/plugin_url_request.h | 17 | ||||
-rw-r--r-- | chrome_frame/urlmon_moniker.cc | 2 | ||||
-rw-r--r-- | chrome_frame/urlmon_upload_data_stream.cc | 100 | ||||
-rw-r--r-- | chrome_frame/urlmon_upload_data_stream.h | 41 | ||||
-rw-r--r-- | chrome_frame/urlmon_upload_data_stream_unittest.cc | 162 | ||||
-rw-r--r-- | chrome_frame/urlmon_url_request.cc | 54 | ||||
-rw-r--r-- | chrome_frame/urlmon_url_request.h | 3 | ||||
-rw-r--r-- | chrome_frame/urlmon_url_request_private.h | 2 | ||||
-rw-r--r-- | chrome_frame/utils.cc | 39 | ||||
-rw-r--r-- | chrome_frame/utils.h | 13 |
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; }; |