Commit 132e281a authored by boliu@chromium.org's avatar boliu@chromium.org

Implement NavigationControllerWebView.PostURL

Used for android WebView.postUrl

HasPostData in NavigationEntry is used to indicate to the renderer that the
navigation is a http post request. The usage here is slightly overloaded.
HasPostData is set when from the renderer side for a http post request. This
change also uses it to indicate a browser initiated http post request from
PostURL. is_post is added to ViewMsg_Navigate_Params.

A BrowserInitiatedPostData field is added to NavigationEntry in order to pass
the post data to the renderer. Similar field added to ViewMsg_Navigate_Params.
This field is only used for temporarily storing and passing post data to the
renderer. Since the post data is also saved in ContentState after loading the
it is cleared when ContentState is set.

BUG=
TEST=New tests passed

Review URL: https://chromiumcodereview.appspot.com/10829044

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149232 0039d316-1c4b-4281-b951-d872f2087c98
parent 81ec7c1a
...@@ -653,6 +653,35 @@ void NavigationControllerImpl::LoadDataWithBaseURL( ...@@ -653,6 +653,35 @@ void NavigationControllerImpl::LoadDataWithBaseURL(
LoadEntry(entry); LoadEntry(entry);
} }
void NavigationControllerImpl::PostURL(
const GURL& url,
const content::Referrer& referrer,
const base::RefCountedMemory& http_body,
bool is_overriding_user_agent) {
// Must be http scheme for a post request.
if (!url.SchemeIs(chrome::kHttpScheme) &&
!url.SchemeIs(chrome::kHttpsScheme)) {
NOTREACHED();
return;
}
needs_reload_ = false;
NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
CreateNavigationEntry(
url,
referrer,
content::PAGE_TRANSITION_TYPED,
false,
std::string(),
browser_context_));
entry->SetIsOverridingUserAgent(is_overriding_user_agent);
entry->SetHasPostData(true);
entry->SetBrowserInitiatedPostData(&http_body);
LoadEntry(entry);
}
void NavigationControllerImpl::DocumentLoadedInFrame() { void NavigationControllerImpl::DocumentLoadedInFrame() {
last_document_loaded_ = base::TimeTicks::Now(); last_document_loaded_ = base::TimeTicks::Now();
} }
...@@ -729,6 +758,9 @@ bool NavigationControllerImpl::RendererDidNavigate( ...@@ -729,6 +758,9 @@ bool NavigationControllerImpl::RendererDidNavigate(
NavigationEntryImpl* active_entry = NavigationEntryImpl* active_entry =
NavigationEntryImpl::FromNavigationEntry(GetActiveEntry()); NavigationEntryImpl::FromNavigationEntry(GetActiveEntry());
active_entry->SetContentState(params.content_state); active_entry->SetContentState(params.content_state);
// No longer needed since content state will hold the post data if any.
active_entry->SetBrowserInitiatedPostData(NULL);
// Once committed, we do not need to track if the entry was initiated by // Once committed, we do not need to track if the entry was initiated by
// the renderer. // the renderer.
......
...@@ -112,6 +112,10 @@ class CONTENT_EXPORT NavigationControllerImpl ...@@ -112,6 +112,10 @@ class CONTENT_EXPORT NavigationControllerImpl
const GURL& base_url, const GURL& base_url,
const GURL& history_url, const GURL& history_url,
bool is_overriding_user_agent) OVERRIDE; bool is_overriding_user_agent) OVERRIDE;
virtual void PostURL(const GURL& url,
const content::Referrer& referrer,
const base::RefCountedMemory& http_body,
bool is_overriding_user_agent) OVERRIDE;
// Returns the index of the specified entry, or -1 if entry is not contained // Returns the index of the specified entry, or -1 if entry is not contained
// in this NavigationController. // in this NavigationController.
......
...@@ -563,6 +563,31 @@ TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) { ...@@ -563,6 +563,31 @@ TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) {
contents()->SetDelegate(NULL); contents()->SetDelegate(NULL);
} }
// Test NavigationEntry is constructed correctly. No other logic tested.
TEST_F(NavigationControllerTest, PostURL) {
NavigationControllerImpl& controller = controller_impl();
const GURL url("http://foo1");
const int length = 5;
const unsigned char* raw_data =
reinterpret_cast<const unsigned char*>("d\n\0a2");
std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
scoped_refptr<base::RefCountedBytes> data =
base::RefCountedBytes::TakeVector(&post_data_vector);
controller.PostURL(url, content::Referrer(), *data.get(), true);
NavigationEntryImpl* post_entry =
NavigationEntryImpl::FromNavigationEntry(
controller.GetPendingEntry());
EXPECT_TRUE(post_entry);
EXPECT_TRUE(post_entry->GetHasPostData());
EXPECT_EQ(data->front(),
post_entry->GetBrowserInitiatedPostData()->front());
}
TEST_F(NavigationControllerTest, Reload) { TEST_F(NavigationControllerTest, Reload) {
NavigationControllerImpl& controller = controller_impl(); NavigationControllerImpl& controller = controller_impl();
TestNotificationTracker notifications; TestNotificationTracker notifications;
......
...@@ -212,6 +212,17 @@ int64 NavigationEntryImpl::GetPostID() const { ...@@ -212,6 +212,17 @@ int64 NavigationEntryImpl::GetPostID() const {
return post_id_; return post_id_;
} }
void NavigationEntryImpl::SetBrowserInitiatedPostData(
const base::RefCountedMemory* data) {
browser_initiated_post_data_ = data;
}
const base::RefCountedMemory*
NavigationEntryImpl::GetBrowserInitiatedPostData() const {
return browser_initiated_post_data_.get();
}
const FaviconStatus& NavigationEntryImpl::GetFavicon() const { const FaviconStatus& NavigationEntryImpl::GetFavicon() const {
return favicon_; return favicon_;
} }
......
...@@ -57,6 +57,10 @@ class CONTENT_EXPORT NavigationEntryImpl ...@@ -57,6 +57,10 @@ class CONTENT_EXPORT NavigationEntryImpl
virtual bool GetHasPostData() const OVERRIDE; virtual bool GetHasPostData() const OVERRIDE;
virtual void SetPostID(int64 post_id) OVERRIDE; virtual void SetPostID(int64 post_id) OVERRIDE;
virtual int64 GetPostID() const OVERRIDE; virtual int64 GetPostID() const OVERRIDE;
virtual void SetBrowserInitiatedPostData(
const base::RefCountedMemory* data) OVERRIDE;
virtual const base::RefCountedMemory*
GetBrowserInitiatedPostData() const OVERRIDE;
virtual const FaviconStatus& GetFavicon() const OVERRIDE; virtual const FaviconStatus& GetFavicon() const OVERRIDE;
virtual FaviconStatus& GetFavicon() OVERRIDE; virtual FaviconStatus& GetFavicon() OVERRIDE;
virtual const SSLStatus& GetSSL() const OVERRIDE; virtual const SSLStatus& GetSSL() const OVERRIDE;
...@@ -185,7 +189,13 @@ class CONTENT_EXPORT NavigationEntryImpl ...@@ -185,7 +189,13 @@ class CONTENT_EXPORT NavigationEntryImpl
GURL original_request_url_; GURL original_request_url_;
bool is_overriding_user_agent_; bool is_overriding_user_agent_;
// This member is not persisted with sesssion restore. // This member is not persisted with session restore because it is transient.
// If the post request succeeds, this field is cleared since the same
// information is stored in |content_state_| above. It is also only shallow
// copied with compiler provided copy constructor.
scoped_refptr<const base::RefCountedMemory> browser_initiated_post_data_;
// This member is not persisted with session restore.
std::string extra_headers_; std::string extra_headers_;
// Used for specifying base URL for pages loaded via data URLs. Not persisted. // Used for specifying base URL for pages loaded via data URLs. Not persisted.
......
...@@ -185,6 +185,19 @@ TEST_F(NavigationEntryTest, NavigationEntryAccessors) { ...@@ -185,6 +185,19 @@ TEST_F(NavigationEntryTest, NavigationEntryAccessors) {
EXPECT_FALSE(entry2_.get()->GetIsOverridingUserAgent()); EXPECT_FALSE(entry2_.get()->GetIsOverridingUserAgent());
entry2_.get()->SetIsOverridingUserAgent(true); entry2_.get()->SetIsOverridingUserAgent(true);
EXPECT_TRUE(entry2_.get()->GetIsOverridingUserAgent()); EXPECT_TRUE(entry2_.get()->GetIsOverridingUserAgent());
// Browser initiated post data
EXPECT_EQ(NULL, entry1_.get()->GetBrowserInitiatedPostData());
EXPECT_EQ(NULL, entry2_.get()->GetBrowserInitiatedPostData());
const int length = 11;
const unsigned char* raw_data =
reinterpret_cast<const unsigned char*>("post\n\n\0data");
std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
scoped_refptr<base::RefCountedBytes> post_data =
base::RefCountedBytes::TakeVector(&post_data_vector);
entry2_.get()->SetBrowserInitiatedPostData(post_data.get());
EXPECT_EQ(post_data->front(),
entry2_.get()->GetBrowserInitiatedPostData()->front());
} }
} // namespace content } // namespace content
...@@ -236,6 +236,14 @@ void MakeNavigateParams(const NavigationEntryImpl& entry, ...@@ -236,6 +236,14 @@ void MakeNavigateParams(const NavigationEntryImpl& entry,
params->allow_download = !entry.IsViewSourceMode(); params->allow_download = !entry.IsViewSourceMode();
params->embedder_channel_name = embedder_channel_name; params->embedder_channel_name = embedder_channel_name;
params->embedder_container_id = embedder_container_id; params->embedder_container_id = embedder_container_id;
params->is_post = entry.GetHasPostData();
if(entry.GetBrowserInitiatedPostData()) {
params->browser_initiated_post_data.assign(
entry.GetBrowserInitiatedPostData()->front(),
entry.GetBrowserInitiatedPostData()->front() +
entry.GetBrowserInitiatedPostData()->size());
}
if (delegate) if (delegate)
delegate->AddNavigationHeaders(params->url, &params->extra_headers); delegate->AddNavigationHeaders(params->url, &params->extra_headers);
......
...@@ -693,6 +693,13 @@ IPC_STRUCT_BEGIN(ViewMsg_Navigate_Params) ...@@ -693,6 +693,13 @@ IPC_STRUCT_BEGIN(ViewMsg_Navigate_Params)
// Whether or not the user agent override string should be used. // Whether or not the user agent override string should be used.
IPC_STRUCT_MEMBER(bool, is_overriding_user_agent) IPC_STRUCT_MEMBER(bool, is_overriding_user_agent)
// True if this was a post request.
IPC_STRUCT_MEMBER(bool, is_post)
// If is_post is true, holds the post_data information from browser. Empty
// otherwise.
IPC_STRUCT_MEMBER(std::vector<unsigned char>, browser_initiated_post_data)
IPC_STRUCT_END() IPC_STRUCT_END()
IPC_STRUCT_BEGIN(ViewMsg_New_Params) IPC_STRUCT_BEGIN(ViewMsg_New_Params)
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef CONTENT_PUBLIC_BROWSER_NAVIGATION_CONTROLLER_WEBVIEW_H_ #ifndef CONTENT_PUBLIC_BROWSER_NAVIGATION_CONTROLLER_WEBVIEW_H_
#define CONTENT_PUBLIC_BROWSER_NAVIGATION_CONTROLLER_WEBVIEW_H_ #define CONTENT_PUBLIC_BROWSER_NAVIGATION_CONTROLLER_WEBVIEW_H_
#include "base/memory/ref_counted_memory.h"
class GURL; class GURL;
namespace content { namespace content {
...@@ -27,6 +29,12 @@ class NavigationControllerWebView { ...@@ -27,6 +29,12 @@ class NavigationControllerWebView {
const GURL& base_url, const GURL& base_url,
const GURL& history_url, const GURL& history_url,
bool is_overriding_user_agent) = 0; bool is_overriding_user_agent) = 0;
// Used to directly send a http post request with a raw http body provided.
virtual void PostURL(const GURL& url,
const content::Referrer& referrer,
const base::RefCountedMemory& http_body,
bool is_overriding_user_agent) = 0;
}; };
} // namespace content } // namespace content
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <string> #include <string>
#include "base/memory/ref_counted_memory.h"
#include "base/string16.h" #include "base/string16.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/public/common/page_transition_types.h" #include "content/public/common/page_transition_types.h"
...@@ -125,8 +126,10 @@ class NavigationEntry { ...@@ -125,8 +126,10 @@ class NavigationEntry {
// have to be reposted to reload the page properly. This flag indicates // have to be reposted to reload the page properly. This flag indicates
// whether the page had post data. // whether the page had post data.
// //
// The actual post data is stored in the content_state and is extracted by // The actual post data is stored either in
// WebKit to actually make the request. // 1) browser_initiated_post_data when a new post data request is started.
// 2) content_state when a post request has started and is extracted by
// WebKit to actually make the request.
virtual void SetHasPostData(bool has_post_data) = 0; virtual void SetHasPostData(bool has_post_data) = 0;
virtual bool GetHasPostData() const = 0; virtual bool GetHasPostData() const = 0;
...@@ -134,6 +137,17 @@ class NavigationEntry { ...@@ -134,6 +137,17 @@ class NavigationEntry {
virtual void SetPostID(int64 post_id) = 0; virtual void SetPostID(int64 post_id) = 0;
virtual int64 GetPostID() const = 0; virtual int64 GetPostID() const = 0;
// Holds the raw post data of a browser initiated post request.
// For efficiency, this should be cleared when content_state is populated
// since the data is duplicated.
// Note, this field:
// 1) is not persisted in session restore.
// 2) is shallow copied with the static copy Create method above.
// 3) may be NULL so check before use.
virtual void SetBrowserInitiatedPostData(
const base::RefCountedMemory* data) = 0;
virtual const base::RefCountedMemory* GetBrowserInitiatedPostData() const = 0;
// The favicon data and tracking information. See content::FaviconStatus. // The favicon data and tracking information. See content::FaviconStatus.
virtual const FaviconStatus& GetFavicon() const = 0; virtual const FaviconStatus& GetFavicon() const = 0;
virtual FaviconStatus& GetFavicon() = 0; virtual FaviconStatus& GetFavicon() = 0;
......
...@@ -21,14 +21,18 @@ ...@@ -21,14 +21,18 @@
#include "content/test/mock_keyboard.h" #include "content/test/mock_keyboard.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebData.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebHTTPBody.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLError.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLError.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebHistoryItem.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebIntentServiceInfo.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebIntentServiceInfo.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebWindowFeatures.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebWindowFeatures.h"
#include "ui/base/keycodes/keyboard_codes.h" #include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/range/range.h" #include "ui/base/range/range.h"
#include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/codec/jpeg_codec.h"
#include "webkit/glue/glue_serialize.h"
#include "webkit/glue/web_io_operators.h" #include "webkit/glue/web_io_operators.h"
#if defined(OS_LINUX) && !defined(USE_AURA) #if defined(OS_LINUX) && !defined(USE_AURA)
...@@ -300,6 +304,48 @@ TEST_F(RenderViewImplTest, OnNavStateChanged) { ...@@ -300,6 +304,48 @@ TEST_F(RenderViewImplTest, OnNavStateChanged) {
ViewHostMsg_UpdateState::ID)); ViewHostMsg_UpdateState::ID));
} }
TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
ViewMsg_Navigate_Params nav_params;
// An http url will trigger a resource load so cannot be used here.
nav_params.url = GURL("data:text/html,<div>Page</div>");
nav_params.navigation_type = ViewMsg_Navigate_Type::NORMAL;
nav_params.transition = content::PAGE_TRANSITION_TYPED;
nav_params.page_id = -1;
nav_params.is_post = true;
// Set up post data.
const unsigned char* raw_data = reinterpret_cast<const unsigned char*>(
"post \0\ndata");
const unsigned int length = 11;
const std::vector<unsigned char> post_data(raw_data, raw_data + length);
nav_params.browser_initiated_post_data = post_data;
view()->OnNavigate(nav_params);
ProcessPendingMessages();
const IPC::Message* frame_navigate_msg =
render_thread_->sink().GetUniqueMessageMatching(
ViewHostMsg_FrameNavigate::ID);
EXPECT_TRUE(frame_navigate_msg);
ViewHostMsg_FrameNavigate::Param host_nav_params;
ViewHostMsg_FrameNavigate::Read(frame_navigate_msg, &host_nav_params);
EXPECT_TRUE(host_nav_params.a.is_post);
// Check post data sent to browser matches
EXPECT_FALSE(host_nav_params.a.content_state.empty());
const WebKit::WebHistoryItem item = webkit_glue::HistoryItemFromString(
host_nav_params.a.content_state);
WebKit::WebHTTPBody body = item.httpBody();
WebKit::WebHTTPBody::Element element;
bool successful = body.elementAt(0, element);
EXPECT_TRUE(successful);
EXPECT_EQ(WebKit::WebHTTPBody::Element::TypeData, element.type);
EXPECT_EQ(length, element.data.size());
EXPECT_EQ(0, memcmp(raw_data, element.data.data(), length));
}
TEST_F(RenderViewImplTest, DecideNavigationPolicy) { TEST_F(RenderViewImplTest, DecideNavigationPolicy) {
WebUITestClient client; WebUITestClient client;
WebUITestBrowserClient browser_client; WebUITestBrowserClient browser_client;
......
...@@ -146,6 +146,7 @@ ...@@ -146,6 +146,7 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebDragData.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebDragData.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGraphicsContext3D.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGraphicsContext3D.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebHTTPBody.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebImage.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebImage.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPeerConnection00Handler.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPeerConnection00Handler.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPeerConnection00HandlerClient.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPeerConnection00HandlerClient.h"
...@@ -235,6 +236,7 @@ using WebKit::WebFormElement; ...@@ -235,6 +236,7 @@ using WebKit::WebFormElement;
using WebKit::WebFrame; using WebKit::WebFrame;
using WebKit::WebGraphicsContext3D; using WebKit::WebGraphicsContext3D;
using WebKit::WebHistoryItem; using WebKit::WebHistoryItem;
using WebKit::WebHTTPBody;
using WebKit::WebIconURL; using WebKit::WebIconURL;
using WebKit::WebImage; using WebKit::WebImage;
using WebKit::WebInputElement; using WebKit::WebInputElement;
...@@ -1088,6 +1090,20 @@ void RenderViewImpl::OnNavigate(const ViewMsg_Navigate_Params& params) { ...@@ -1088,6 +1090,20 @@ void RenderViewImpl::OnNavigate(const ViewMsg_Navigate_Params& params) {
WebString::fromUTF8(i.values())); WebString::fromUTF8(i.values()));
} }
} }
if (params.is_post) {
request.setHTTPMethod(WebString::fromUTF8("POST"));
// Set post data.
WebHTTPBody http_body;
http_body.initialize();
http_body.appendData(WebData(
reinterpret_cast<const char*>(
&params.browser_initiated_post_data.front()),
params.browser_initiated_post_data.size()));
request.setHTTPBody(http_body);
}
main_frame->loadRequest(request); main_frame->loadRequest(request);
} }
......
...@@ -795,6 +795,7 @@ class RenderViewImpl : public RenderWidget, ...@@ -795,6 +795,7 @@ class RenderViewImpl : public RenderWidget,
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, UpdateTargetURLWithInvalidURL); FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, UpdateTargetURLWithInvalidURL);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
GetCompositionCharacterBoundsTest); GetCompositionCharacterBoundsTest);
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, OnNavigationHttpPost);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
FRIEND_TEST_ALL_PREFIXES(RenderViewTest, MacTestCmdUp); FRIEND_TEST_ALL_PREFIXES(RenderViewTest, MacTestCmdUp);
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment