diff options
author | bryner@chromium.org <bryner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-22 19:47:19 +0000 |
---|---|---|
committer | bryner@chromium.org <bryner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-22 19:47:19 +0000 |
commit | 6d81b488e8cc5e10eaeca0a4ee4819dc3f469a24 (patch) | |
tree | e628aa40ac26d26a6a9a46374001be983e7a7f41 | |
parent | f19572134235f4cceb76e85e1c064ba668bbd3bd (diff) | |
download | chromium_src-6d81b488e8cc5e10eaeca0a4ee4819dc3f469a24.zip chromium_src-6d81b488e8cc5e10eaeca0a4ee4819dc3f469a24.tar.gz chromium_src-6d81b488e8cc5e10eaeca0a4ee4819dc3f469a24.tar.bz2 |
Propagate the remote socket address to URLRequest and to ViewHostMsg_FrameNavigate.
This will be used to run pre-classification checks for client-side phishing
detection, and will also enable the socket address to be exposed via the
webRequest extension API. This is adapted from the original patch by pmarks
on http://codereview.chromium.org/6369003/ .
BUG=51663
TEST=added socket address checks to various unittests
Review URL: http://codereview.chromium.org/6488010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75620 0039d316-1c4b-4281-b951-d872f2087c98
37 files changed, 318 insertions, 9 deletions
diff --git a/base/pickle.cc b/base/pickle.cc index e7d5768..116d3f1 100644 --- a/base/pickle.cc +++ b/base/pickle.cc @@ -157,6 +157,20 @@ bool Pickle::ReadSize(void** iter, size_t* result) const { return true; } +bool Pickle::ReadUInt16(void** iter, uint16* result) const { + DCHECK(iter); + if (!*iter) + *iter = const_cast<char*>(payload()); + + if (!IteratorHasRoomFor(*iter, sizeof(*result))) + return false; + + memcpy(result, *iter, sizeof(*result)); + + UpdateIter(iter, sizeof(*result)); + return true; +} + bool Pickle::ReadUInt32(void** iter, uint32* result) const { DCHECK(iter); if (!*iter) diff --git a/base/pickle.h b/base/pickle.h index ad08b7c..052aa33 100644 --- a/base/pickle.h +++ b/base/pickle.h @@ -68,6 +68,7 @@ class Pickle { bool ReadInt(void** iter, int* result) const; bool ReadLong(void** iter, long* result) const; bool ReadSize(void** iter, size_t* result) const; + bool ReadUInt16(void** iter, uint16* result) const; bool ReadUInt32(void** iter, uint32* result) const; bool ReadInt64(void** iter, int64* result) const; bool ReadUInt64(void** iter, uint64* result) const; @@ -97,6 +98,9 @@ class Pickle { bool WriteSize(size_t value) { return WriteBytes(&value, sizeof(value)); } + bool WriteUInt16(uint16 value) { + return WriteBytes(&value, sizeof(value)); + } bool WriteUInt32(uint32 value) { return WriteBytes(&value, sizeof(value)); } diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc index 39eaa1b..51330c7 100644 --- a/base/pickle_unittest.cc +++ b/base/pickle_unittest.cc @@ -19,6 +19,7 @@ const char testdata[] = "AAA\0BBB\0"; const int testdatalen = arraysize(testdata) - 1; const bool testbool1 = false; const bool testbool2 = true; +const uint16 testuint16 = 32123; // checks that the result void VerifyResult(const Pickle& pickle) { @@ -42,6 +43,10 @@ void VerifyResult(const Pickle& pickle) { EXPECT_TRUE(pickle.ReadBool(&iter, &outbool)); EXPECT_EQ(testbool2, outbool); + uint16 outuint16; + EXPECT_TRUE(pickle.ReadUInt16(&iter, &outuint16)); + EXPECT_EQ(testuint16, outuint16); + const char* outdata; int outdatalen; EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen)); @@ -66,6 +71,7 @@ TEST(PickleTest, EncodeDecode) { EXPECT_TRUE(pickle.WriteWString(testwstr)); EXPECT_TRUE(pickle.WriteBool(testbool1)); EXPECT_TRUE(pickle.WriteBool(testbool2)); + EXPECT_TRUE(pickle.WriteUInt16(testuint16)); EXPECT_TRUE(pickle.WriteData(testdata, testdatalen)); // Over allocate BeginWriteData so we can test TrimWriteData. diff --git a/chrome/browser/renderer_host/test/render_view_host_browsertest.cc b/chrome/browser/renderer_host/test/render_view_host_browsertest.cc index 6e37723..3081786 100644 --- a/chrome/browser/renderer_host/test/render_view_host_browsertest.cc +++ b/chrome/browser/renderer_host/test/render_view_host_browsertest.cc @@ -9,10 +9,13 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_contents_observer.h" #include "chrome/browser/tab_contents/tab_specific_content_settings.h" #include "chrome/browser/ui/browser.h" +#include "chrome/common/render_messages_params.h" #include "chrome/test/in_process_browser_test.h" #include "chrome/test/ui_test_utils.h" +#include "net/base/host_port_pair.h" #include "net/test/test_server.h" typedef std::pair<int, Value*> ExecuteDetailType; @@ -223,3 +226,43 @@ IN_PROC_BROWSER_TEST_F(RenderViewHostTest, RedirectLoopCookies) { EXPECT_TRUE(tab_contents->GetTabSpecificContentSettings()->IsContentBlocked( CONTENT_SETTINGS_TYPE_COOKIES)); } + +class RenderViewHostTestTabContentsObserver : public TabContentsObserver { + public: + explicit RenderViewHostTestTabContentsObserver(TabContents* tab_contents) + : TabContentsObserver(tab_contents), + navigation_count_(0) {} + virtual ~RenderViewHostTestTabContentsObserver() {} + + virtual void DidNavigateMainFramePostCommit( + const NavigationController::LoadCommittedDetails& details, + const ViewHostMsg_FrameNavigate_Params& params) { + observed_socket_address_ = params.socket_address; + ++navigation_count_; + } + + const net::HostPortPair& observed_socket_address() const { + return observed_socket_address_; + } + + int navigation_count() const { return navigation_count_; } + + private: + net::HostPortPair observed_socket_address_; + int navigation_count_; + + DISALLOW_COPY_AND_ASSIGN(RenderViewHostTestTabContentsObserver); +}; + +IN_PROC_BROWSER_TEST_F(RenderViewHostTest, FrameNavigateSocketAddress) { + ASSERT_TRUE(test_server()->Start()); + RenderViewHostTestTabContentsObserver observer( + browser()->GetSelectedTabContents()); + + GURL test_url = test_server()->GetURL("files/simple.html"); + ui_test_utils::NavigateToURL(browser(), test_url); + + EXPECT_EQ(test_server()->host_port_pair().ToString(), + observer.observed_socket_address().ToString()); + EXPECT_EQ(1, observer.navigation_count()); +} diff --git a/chrome/browser/renderer_host/test/test_render_view_host.cc b/chrome/browser/renderer_host/test/test_render_view_host.cc index 4bab6c8..a711ff7 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.cc +++ b/chrome/browser/renderer_host/test/test_render_view_host.cc @@ -98,6 +98,8 @@ void TestRenderViewHost::SendNavigateWithTransition( params.is_content_filtered = false; params.was_within_same_page = false; params.http_status_code = 0; + params.socket_address.set_host("2001:db8::1"); + params.socket_address.set_port(80); ViewHostMsg_FrameNavigate msg(1, params); OnMsgNavigate(msg); diff --git a/chrome/common/common_param_traits.cc b/chrome/common/common_param_traits.cc index 64fa35c9..042b2ab 100644 --- a/chrome/common/common_param_traits.cc +++ b/chrome/common/common_param_traits.cc @@ -11,6 +11,7 @@ #include "chrome/common/thumbnail_score.h" #include "chrome/common/web_apps.h" #include "googleurl/src/gurl.h" +#include "net/base/host_port_pair.h" #include "net/base/upload_data.h" #include "printing/backend/print_backend.h" #include "printing/native_metafile.h" @@ -290,6 +291,27 @@ void ParamTraits<WebApplicationInfo>::Log(const WebApplicationInfo& p, l->append("<WebApplicationInfo>"); } +void ParamTraits<net::HostPortPair>::Write(Message* m, const param_type& p) { + WriteParam(m, p.host()); + WriteParam(m, p.port()); +} + +bool ParamTraits<net::HostPortPair>::Read(const Message* m, void** iter, + param_type* r) { + std::string host; + uint16 port; + if (!ReadParam(m, iter, &host) || !ReadParam(m, iter, &port)) + return false; + + r->set_host(host); + r->set_port(port); + return true; +} + +void ParamTraits<net::HostPortPair>::Log(const param_type& p, std::string* l) { + l->append(p.ToString()); +} + void ParamTraits<net::URLRequestStatus>::Write(Message* m, const param_type& p) { WriteParam(m, static_cast<int>(p.status())); diff --git a/chrome/common/common_param_traits.h b/chrome/common/common_param_traits.h index f1e8cb0..860dcc6 100644 --- a/chrome/common/common_param_traits.h +++ b/chrome/common/common_param_traits.h @@ -50,6 +50,7 @@ class Size; } // namespace gfx namespace net { +class HostPortPair; class UploadData; class URLRequestStatus; } @@ -263,6 +264,15 @@ struct ParamTraits<TransportDIB::Id> { }; #endif +// Traits for HostPortPair +template<> +struct ParamTraits<net::HostPortPair> { + typedef net::HostPortPair param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + // Traits for URLRequestStatus template <> struct ParamTraits<net::URLRequestStatus> { diff --git a/chrome/common/common_param_traits_unittest.cc b/chrome/common/common_param_traits_unittest.cc index a11ddd1..9a95c0f0 100644 --- a/chrome/common/common_param_traits_unittest.cc +++ b/chrome/common/common_param_traits_unittest.cc @@ -12,6 +12,7 @@ #include "googleurl/src/gurl.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_utils.h" +#include "net/base/host_port_pair.h" #include "printing/backend/print_backend.h" #include "printing/native_metafile.h" #include "printing/page_range.h" @@ -286,3 +287,16 @@ TEST(IPCMessageTest, PrinterCapsAndDefaults) { EXPECT_TRUE(input.defaults_mime_type == output.defaults_mime_type); } +// Tests net::HostPortPair serialization +TEST(IPCMessageTest, HostPortPair) { + net::HostPortPair input("host.com", 12345); + + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::ParamTraits<net::HostPortPair>::Write(&msg, input); + + net::HostPortPair output; + void* iter = NULL; + EXPECT_TRUE(IPC::ParamTraits<net::HostPortPair>::Read(&msg, &iter, &output)); + EXPECT_EQ(input.host(), output.host()); + EXPECT_EQ(input.port(), output.port()); +} diff --git a/chrome/common/render_messages.cc b/chrome/common/render_messages.cc index 5df43f7..2010064 100644 --- a/chrome/common/render_messages.cc +++ b/chrome/common/render_messages.cc @@ -443,6 +443,7 @@ void ParamTraits<webkit_glue::ResourceResponseInfo>::Write( WriteParam(m, p.was_npn_negotiated); WriteParam(m, p.was_alternate_protocol_available); WriteParam(m, p.was_fetched_via_proxy); + WriteParam(m, p.socket_address); } bool ParamTraits<webkit_glue::ResourceResponseInfo>::Read( @@ -465,7 +466,8 @@ bool ParamTraits<webkit_glue::ResourceResponseInfo>::Read( ReadParam(m, iter, &r->was_fetched_via_spdy) && ReadParam(m, iter, &r->was_npn_negotiated) && ReadParam(m, iter, &r->was_alternate_protocol_available) && - ReadParam(m, iter, &r->was_fetched_via_proxy); + ReadParam(m, iter, &r->was_fetched_via_proxy) && + ReadParam(m, iter, &r->socket_address); } void ParamTraits<webkit_glue::ResourceResponseInfo>::Log( @@ -506,6 +508,8 @@ void ParamTraits<webkit_glue::ResourceResponseInfo>::Log( LogParam(p.was_alternate_protocol_available, l); l->append(", "); LogParam(p.was_fetched_via_proxy, l); + l->append(", "); + LogParam(p.socket_address, l); l->append(")"); } diff --git a/chrome/common/render_messages_params.cc b/chrome/common/render_messages_params.cc index 8e4a17b..79a941f 100644 --- a/chrome/common/render_messages_params.cc +++ b/chrome/common/render_messages_params.cc @@ -772,6 +772,7 @@ void ParamTraits<ViewHostMsg_FrameNavigate_Params>::Write(Message* m, WriteParam(m, p.is_content_filtered); WriteParam(m, p.was_within_same_page); WriteParam(m, p.http_status_code); + WriteParam(m, p.socket_address); } bool ParamTraits<ViewHostMsg_FrameNavigate_Params>::Read(const Message* m, @@ -794,7 +795,8 @@ bool ParamTraits<ViewHostMsg_FrameNavigate_Params>::Read(const Message* m, ReadParam(m, iter, &p->is_post) && ReadParam(m, iter, &p->is_content_filtered) && ReadParam(m, iter, &p->was_within_same_page) && - ReadParam(m, iter, &p->http_status_code); + ReadParam(m, iter, &p->http_status_code) && + ReadParam(m, iter, &p->socket_address); } void ParamTraits<ViewHostMsg_FrameNavigate_Params>::Log(const param_type& p, @@ -833,6 +835,8 @@ void ParamTraits<ViewHostMsg_FrameNavigate_Params>::Log(const param_type& p, LogParam(p.was_within_same_page, l); l->append(", "); LogParam(p.http_status_code, l); + l->append(", "); + LogParam(p.socket_address, l); l->append(")"); } diff --git a/chrome/common/render_messages_params.h b/chrome/common/render_messages_params.h index d5bd158..fbd9dbb 100644 --- a/chrome/common/render_messages_params.h +++ b/chrome/common/render_messages_params.h @@ -28,6 +28,7 @@ #include "googleurl/src/gurl.h" #include "ipc/ipc_param_traits.h" #include "media/audio/audio_parameters.h" +#include "net/base/host_port_pair.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h" #include "ui/gfx/rect.h" #include "ui/gfx/size.h" @@ -303,6 +304,9 @@ struct ViewHostMsg_FrameNavigate_Params { // The status code of the HTTP request. int http_status_code; + + // Remote address of the socket which fetched this resource. + net::HostPortPair socket_address; }; // Values that may be OR'd together to form the 'flags' parameter of a diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 53697cfef..97d38bf 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -1642,6 +1642,8 @@ void RenderView::UpdateURL(WebFrame* frame) { params.page_id = page_id_; params.frame_id = frame->identifier(); params.is_content_filtered = response.isContentFiltered(); + params.socket_address.set_host(response.remoteIPAddress().utf8()); + params.socket_address.set_port(response.remotePort()); params.was_within_same_page = navigation_state->was_within_same_page(); if (!navigation_state->security_info().empty()) { // SSL state specified in the request takes precedence over the one in the diff --git a/content/browser/renderer_host/resource_dispatcher_host.cc b/content/browser/renderer_host/resource_dispatcher_host.cc index 94f5c5e..47709e5 100644 --- a/content/browser/renderer_host/resource_dispatcher_host.cc +++ b/content/browser/renderer_host/resource_dispatcher_host.cc @@ -183,6 +183,7 @@ void PopulateResourceResponse(net::URLRequest* request, request->was_alternate_protocol_available(); response->response_head.was_fetched_via_proxy = request->was_fetched_via_proxy(); + response->response_head.socket_address = request->GetSocketAddress(); appcache::AppCacheInterceptor::GetExtraResponseInfo( request, &response->response_head.appcache_id, diff --git a/net/base/host_port_pair.cc b/net/base/host_port_pair.cc index 1c4406f..5164fcf 100644 --- a/net/base/host_port_pair.cc +++ b/net/base/host_port_pair.cc @@ -7,6 +7,8 @@ #include "base/string_util.h" #include "base/stringprintf.h" #include "googleurl/src/gurl.h" +#include "net/base/net_util.h" +#include "net/base/sys_addrinfo.h" namespace net { @@ -19,6 +21,12 @@ HostPortPair HostPortPair::FromURL(const GURL& url) { return HostPortPair(url.HostNoBrackets(), url.EffectiveIntPort()); } +// static +HostPortPair HostPortPair::FromAddrInfo(const struct addrinfo* ai) { + return HostPortPair(NetAddressToString(ai), + GetPortFromSockaddr(ai->ai_addr, ai->ai_addrlen)); +} + std::string HostPortPair::ToString() const { return base::StringPrintf("%s:%u", HostForURL().c_str(), port_); } diff --git a/net/base/host_port_pair.h b/net/base/host_port_pair.h index 2c7bb9f..7488e6c 100644 --- a/net/base/host_port_pair.h +++ b/net/base/host_port_pair.h @@ -9,6 +9,7 @@ #include <string> #include "base/basictypes.h" +struct addrinfo; class GURL; namespace net { @@ -22,6 +23,9 @@ class HostPortPair { // Creates a HostPortPair for the origin of |url|. static HostPortPair FromURL(const GURL& url); + // Creates a HostPortPair from an addrinfo struct. + static HostPortPair FromAddrInfo(const struct addrinfo* ai); + // TODO(willchan): Define a functor instead. // Comparator function so this can be placed in a std::map. bool operator<(const HostPortPair& other) const { diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc index d012818..3f35c83 100644 --- a/net/ftp/ftp_network_transaction.cc +++ b/net/ftp/ftp_network_transaction.cc @@ -9,6 +9,7 @@ #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "net/base/address_list.h" #include "net/base/connection_type_histograms.h" #include "net/base/escape.h" #include "net/base/net_errors.h" @@ -620,8 +621,15 @@ int FtpNetworkTransaction::DoCtrlConnect() { } int FtpNetworkTransaction::DoCtrlConnectComplete(int result) { - if (result == OK) - next_state_ = STATE_CTRL_READ; + if (result == OK) { + // Put the peer's IP address and port into the response. + AddressList address; + result = ctrl_socket_->GetPeerAddress(&address); + if (result == OK) { + response_.socket_address = HostPortPair::FromAddrInfo(address.head()); + next_state_ = STATE_CTRL_READ; + } + } return result; } diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc index 8da3baf..1d86fba 100644 --- a/net/ftp/ftp_network_transaction_unittest.cc +++ b/net/ftp/ftp_network_transaction_unittest.cc @@ -9,6 +9,7 @@ #include "base/ref_counted.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "net/base/host_port_pair.h" #include "net/base/io_buffer.h" #include "net/base/mock_host_resolver.h" #include "net/base/net_util.h" @@ -831,6 +832,9 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransaction) { EXPECT_TRUE(transaction_.GetResponseInfo()->is_directory_listing); EXPECT_EQ(-1, transaction_.GetResponseInfo()->expected_content_size); + EXPECT_EQ("192.0.2.33", + transaction_.GetResponseInfo()->socket_address.host()); + EXPECT_EQ(0, transaction_.GetResponseInfo()->socket_address.port()); } TEST_F(FtpNetworkTransactionTest, DirectoryTransactionWithPasvFallback) { @@ -904,6 +908,9 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransaction) { // We pass an artificial value of 18 as a response to the SIZE command. EXPECT_EQ(18, transaction_.GetResponseInfo()->expected_content_size); + EXPECT_EQ("192.0.2.33", + transaction_.GetResponseInfo()->socket_address.host()); + EXPECT_EQ(0, transaction_.GetResponseInfo()->socket_address.port()); } TEST_F(FtpNetworkTransactionTest, DownloadTransactionWithPasvFallback) { diff --git a/net/ftp/ftp_response_info.h b/net/ftp/ftp_response_info.h index 0c8884c..9db9018 100644 --- a/net/ftp/ftp_response_info.h +++ b/net/ftp/ftp_response_info.h @@ -7,6 +7,7 @@ #pragma once #include "base/time.h" +#include "net/base/host_port_pair.h" namespace net { @@ -36,6 +37,9 @@ class FtpResponseInfo { // True if the response data is of a directory listing. bool is_directory_listing; + + // Remote address of the socket which fetched this resource. + HostPortPair socket_address; }; } // namespace net diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index bf8cb6b..8d5fea4 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -11,6 +11,7 @@ #include "base/stringprintf.h" #include "net/base/cache_type.h" #include "net/base/cert_status_flags.h" +#include "net/base/host_port_pair.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/base/net_log_unittest.h" @@ -3978,6 +3979,31 @@ TEST(HttpCache, WriteResponseInfo_Truncated) { entry->Close(); } +// Tests basic pickling/unpickling of HttpResponseInfo. +TEST(HttpCache, PersistHttpResponseInfo) { + // Set some fields (add more if needed.) + net::HttpResponseInfo response1; + response1.was_cached = false; + response1.socket_address = net::HostPortPair("1.2.3.4", 80); + response1.headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK"); + + // Pickle. + Pickle pickle; + response1.Persist(&pickle, false, false); + + // Unpickle. + net::HttpResponseInfo response2; + bool response_truncated; + EXPECT_TRUE(response2.InitFromPickle(pickle, &response_truncated)); + EXPECT_FALSE(response_truncated); + + // Verify fields. + EXPECT_TRUE(response2.was_cached); // InitFromPickle sets this flag. + EXPECT_EQ("1.2.3.4", response2.socket_address.host()); + EXPECT_EQ(80, response2.socket_address.port()); + EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); +} + // Tests that we delete an entry when the request is cancelled before starting // to read from the network. TEST(HttpCache, DoomOnDestruction) { diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 8c87136..e54edf5 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -175,6 +175,9 @@ class HttpNetworkTransactionTest : public PlatformTest { EXPECT_TRUE(response->headers != NULL); out.status_line = response->headers->GetStatusLine(); + EXPECT_EQ("192.0.2.33", response->socket_address.host()); + EXPECT_EQ(0, response->socket_address.port()); + rv = ReadTransaction(trans.get(), &out.response_data); EXPECT_EQ(OK, rv); diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc index 2c23faa..9b3444a 100644 --- a/net/http/http_response_info.cc +++ b/net/http/http_response_info.cc @@ -74,6 +74,7 @@ HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs) was_npn_negotiated(rhs.was_npn_negotiated), was_alternate_protocol_available(rhs.was_alternate_protocol_available), was_fetched_via_proxy(rhs.was_fetched_via_proxy), + socket_address(rhs.socket_address), request_time(rhs.request_time), response_time(rhs.response_time), auth_challenge(rhs.auth_challenge), @@ -93,6 +94,7 @@ HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) { was_npn_negotiated = rhs.was_npn_negotiated; was_alternate_protocol_available = rhs.was_alternate_protocol_available; was_fetched_via_proxy = rhs.was_fetched_via_proxy; + socket_address = rhs.socket_address; request_time = rhs.request_time; response_time = rhs.response_time; auth_challenge = rhs.auth_challenge; @@ -158,6 +160,18 @@ bool HttpResponseInfo::InitFromPickle(const Pickle& pickle, return false; } + // Read socket_address. This was not always present in the response info, + // so we don't fail if it can't be read. If additional fields are added in + // a future version, then they must only be read if this operation succeeds. + std::string socket_address_host; + if (pickle.ReadString(&iter, &socket_address_host)) { + // If the host was written, we always expect the port to follow. + uint16 socket_address_port; + if (!pickle.ReadUInt16(&iter, &socket_address_port)) + return false; + socket_address = HostPortPair(socket_address_host, socket_address_port); + } + was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0; was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0; @@ -223,6 +237,9 @@ void HttpResponseInfo::Persist(Pickle* pickle, if (vary_data.is_valid()) vary_data.Persist(pickle); + + pickle->WriteString(socket_address.host()); + pickle->WriteUInt16(socket_address.port()); } } // namespace net diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h index 4fbea3d..e13f288 100644 --- a/net/http/http_response_info.h +++ b/net/http/http_response_info.h @@ -7,6 +7,7 @@ #pragma once #include "base/time.h" +#include "net/base/host_port_pair.h" #include "net/base/ssl_info.h" #include "net/http/http_vary_data.h" @@ -60,6 +61,15 @@ class HttpResponseInfo { // transparent proxy may have been involved. bool was_fetched_via_proxy; + // Remote address of the socket which fetched this resource. + // + // NOTE: If the response was served from the cache (was_cached is true), + // the socket address will be set to the address that the content came from + // originally. This is true even if the response was re-validated using a + // different remote address, or if some of the content came from a byte-range + // request to a different address. + HostPortPair socket_address; + // The time at which the request was made that resulted in this response. // For cached responses, this is the last time the cache entry was validated. base::Time request_time; diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc index 20ebd87..6621f0b 100644 --- a/net/http/http_stream_parser.cc +++ b/net/http/http_stream_parser.cc @@ -6,6 +6,7 @@ #include "base/compiler_specific.h" #include "base/metrics/histogram.h" +#include "net/base/address_list.h" #include "net/base/auth.h" #include "net/base/io_buffer.h" #include "net/base/ssl_cert_request_info.h" @@ -65,6 +66,14 @@ int HttpStreamParser::SendRequest(const std::string& request_line, request_line, headers))); } response_ = response; + + // Put the peer's IP address and port into the response. + AddressList address; + int result = connection_->socket()->GetPeerAddress(&address); + if (result != OK) + return result; + response_->socket_address = HostPortPair::FromAddrInfo(address.head()); + std::string request = request_line + headers.ToString(); scoped_refptr<StringIOBuffer> headers_io_buf(new StringIOBuffer(request)); request_headers_ = new DrainableIOBuffer(headers_io_buf, @@ -74,7 +83,7 @@ int HttpStreamParser::SendRequest(const std::string& request_line, request_body_->set_chunk_callback(this); io_state_ = STATE_SENDING_HEADERS; - int result = DoLoop(OK); + result = DoLoop(OK); if (result == ERR_IO_PENDING) user_callback_ = callback; diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index d5ee9ae..dc89546 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc @@ -631,7 +631,7 @@ bool MockClientSocket::IsConnectedAndIdle() const { } int MockClientSocket::GetPeerAddress(AddressList* address) const { - return net::SystemHostResolverProc("localhost", ADDRESS_FAMILY_UNSPECIFIED, + return net::SystemHostResolverProc("192.0.2.33", ADDRESS_FAMILY_UNSPECIFIED, 0, address, NULL); } diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc index 6a6abb2..e07578e 100644 --- a/net/spdy/spdy_http_stream.cc +++ b/net/spdy/spdy_http_stream.cc @@ -10,6 +10,8 @@ #include "base/logging.h" #include "base/message_loop.h" +#include "net/base/address_list.h" +#include "net/base/host_port_pair.h" #include "net/base/load_flags.h" #include "net/base/net_util.h" #include "net/http/http_request_headers.h" @@ -230,8 +232,15 @@ int SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers, response_info_ = response; + // Put the peer's IP address and port into the response. + AddressList address; + int result = stream_->GetPeerAddress(&address); + if (result != OK) + return result; + response_info_->socket_address = HostPortPair::FromAddrInfo(address.head()); + bool has_upload_data = request_body_stream_.get() != NULL; - int result = stream_->SendRequest(has_upload_data); + result = stream_->SendRequest(has_upload_data); if (result == ERR_IO_PENDING) { CHECK(!user_callback_); user_callback_ = callback; diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index de248cb..402f2f7 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc @@ -177,10 +177,11 @@ class SpdyNetworkTransactionTest EXPECT_EQ(request_.url.SchemeIs("https"), response->was_npn_negotiated); } + EXPECT_EQ("192.0.2.33", response->socket_address.host()); + EXPECT_EQ(0, response->socket_address.port()); output_.status_line = response->headers->GetStatusLine(); output_.response_info = *response; // Make a copy so we can verify. output_.rv = ReadTransaction(trans_.get(), &output_.response_data); - return; } // Most tests will want to call this function. In particular, the MockReads diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index 9e35fc0..848b810 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc @@ -9,6 +9,7 @@ #include "base/metrics/stats_counters.h" #include "base/singleton.h" #include "base/synchronization/lock.h" +#include "net/base/host_port_pair.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/base/net_log.h" @@ -272,6 +273,11 @@ void URLRequest::GetAllResponseHeaders(string* headers) { } } +HostPortPair URLRequest::GetSocketAddress() const { + DCHECK(job_); + return job_->GetSocketAddress(); +} + net::HttpResponseHeaders* URLRequest::response_headers() const { return response_info_.headers.get(); } diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h index bb08a8f..a2ad24b 100644 --- a/net/url_request/url_request.h +++ b/net/url_request/url_request.h @@ -38,6 +38,7 @@ typedef std::vector<std::string> ResponseCookies; namespace net { class CookieOptions; +class HostPortPair; class IOBuffer; class SSLCertRequestInfo; class UploadData; @@ -416,6 +417,10 @@ class URLRequest : public base::NonThreadSafe { return response_info_.was_fetched_via_proxy; } + // Returns the host and port that the content was fetched from. See + // http_response_info.h for caveats relating to cached content. + HostPortPair GetSocketAddress() const; + // Get all response headers, as a HttpResponseHeaders object. See comments // in HttpResponseHeaders class as to the format of the data. net::HttpResponseHeaders* response_headers() const; diff --git a/net/url_request/url_request_ftp_job.cc b/net/url_request/url_request_ftp_job.cc index 8c170ff..48f0639 100644 --- a/net/url_request/url_request_ftp_job.cc +++ b/net/url_request/url_request_ftp_job.cc @@ -8,6 +8,7 @@ #include "base/message_loop.h" #include "base/utf_string_conversions.h" #include "net/base/auth.h" +#include "net/base/host_port_pair.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" #include "net/ftp/ftp_response_info.h" @@ -52,6 +53,13 @@ bool URLRequestFtpJob::GetMimeType(std::string* mime_type) const { return false; } +HostPortPair URLRequestFtpJob::GetSocketAddress() const { + if (!transaction_.get()) { + return HostPortPair(); + } + return transaction_->GetResponseInfo()->socket_address; +} + URLRequestFtpJob::~URLRequestFtpJob() { } diff --git a/net/url_request/url_request_ftp_job.h b/net/url_request/url_request_ftp_job.h index fe85ba3..84c54e1 100644 --- a/net/url_request/url_request_ftp_job.h +++ b/net/url_request/url_request_ftp_job.h @@ -31,6 +31,7 @@ class URLRequestFtpJob : public URLRequestJob { // Overridden from URLRequestJob: virtual bool GetMimeType(std::string* mime_type) const; + virtual HostPortPair GetSocketAddress() const; private: virtual ~URLRequestFtpJob(); diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index de51284..563c85b 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -16,12 +16,13 @@ #include "net/base/cookie_policy.h" #include "net/base/cookie_store.h" #include "net/base/filter.h" -#include "net/base/transport_security_state.h" +#include "net/base/host_port_pair.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" #include "net/base/sdch_manager.h" #include "net/base/ssl_cert_request_info.h" +#include "net/base/transport_security_state.h" #include "net/http/http_request_headers.h" #include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" @@ -926,6 +927,10 @@ void URLRequestHttpJob::StopCaching() { transaction_->StopCaching(); } +HostPortPair URLRequestHttpJob::GetSocketAddress() const { + return response_info_ ? response_info_->socket_address : HostPortPair(); +} + URLRequestHttpJob::~URLRequestHttpJob() { DCHECK(!sdch_test_control_ || !sdch_test_activated_); if (!IsCachedContent()) { diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h index 3f9356e..e1abf3e 100644 --- a/net/url_request/url_request_http_job.h +++ b/net/url_request/url_request_http_job.h @@ -85,6 +85,7 @@ class URLRequestHttpJob : public URLRequestJob { virtual void ContinueDespiteLastError(); virtual bool ReadRawData(IOBuffer* buf, int buf_size, int *bytes_read); virtual void StopCaching(); + virtual HostPortPair GetSocketAddress() const; // Keep a reference to the url request context to be sure it's not deleted // before us. diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc index ac05127..12c8d2e 100644 --- a/net/url_request/url_request_job.cc +++ b/net/url_request/url_request_job.cc @@ -9,6 +9,7 @@ #include "base/string_number_conversions.h" #include "base/string_util.h" #include "net/base/auth.h" +#include "net/base/host_port_pair.h" #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/mime_util.h" @@ -398,6 +399,10 @@ void URLRequestJob::RecordPacketStats(StatisticSelector statistic) const { } } +HostPortPair URLRequestJob::GetSocketAddress() const { + return HostPortPair(); +} + URLRequestJob::~URLRequestJob() { g_url_request_job_tracker.RemoveJob(this); } diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h index 3ac648b..b6c286a 100644 --- a/net/url_request/url_request_job.h +++ b/net/url_request/url_request_job.h @@ -15,6 +15,7 @@ #include "base/time.h" #include "googleurl/src/gurl.h" #include "net/base/filter.h" +#include "net/base/host_port_pair.h" #include "net/base/load_states.h" @@ -209,6 +210,10 @@ class URLRequestJob : public base::RefCounted<URLRequestJob>, virtual int GetInputStreamBufferSize() const; virtual void RecordPacketStats(StatisticSelector statistic) const; + // Returns the socket address for the connection. + // See url_request.h for details. + virtual HostPortPair GetSocketAddress() const; + protected: friend class base::RefCounted<URLRequestJob>; virtual ~URLRequestJob(); diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 35573ed..3192b39 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -267,6 +267,10 @@ TEST_F(URLRequestTestHTTP, GetTest_NoCache) { EXPECT_EQ(1, d.response_started_count()); EXPECT_FALSE(d.received_data_before_response()); EXPECT_NE(0, d.bytes_received()); + EXPECT_EQ(test_server_.host_port_pair().host(), + r.GetSocketAddress().host()); + EXPECT_EQ(test_server_.host_port_pair().port(), + r.GetSocketAddress().port()); // TODO(eroman): Add back the NetLog tests... } @@ -287,6 +291,10 @@ TEST_F(URLRequestTestHTTP, GetTest) { EXPECT_EQ(1, d.response_started_count()); EXPECT_FALSE(d.received_data_before_response()); EXPECT_NE(0, d.bytes_received()); + EXPECT_EQ(test_server_.host_port_pair().host(), + r.GetSocketAddress().host()); + EXPECT_EQ(test_server_.host_port_pair().port(), + r.GetSocketAddress().port()); } } @@ -335,6 +343,10 @@ TEST_F(HTTPSRequestTest, HTTPSGetTest) { EXPECT_FALSE(d.received_data_before_response()); EXPECT_NE(0, d.bytes_received()); CheckSSLInfo(r.ssl_info()); + EXPECT_EQ(test_server.host_port_pair().host(), + r.GetSocketAddress().host()); + EXPECT_EQ(test_server.host_port_pair().port(), + r.GetSocketAddress().port()); } } @@ -713,6 +725,8 @@ TEST_F(URLRequestTest, AboutBlankTest) { EXPECT_TRUE(!r.is_pending()); EXPECT_FALSE(d.received_data_before_response()); EXPECT_EQ(d.bytes_received(), 0); + EXPECT_EQ("", r.GetSocketAddress().host()); + EXPECT_EQ(0, r.GetSocketAddress().port()); } } @@ -750,6 +764,8 @@ TEST_F(URLRequestTest, DataURLImageTest) { EXPECT_TRUE(!r.is_pending()); EXPECT_FALSE(d.received_data_before_response()); EXPECT_EQ(d.bytes_received(), 911); + EXPECT_EQ("", r.GetSocketAddress().host()); + EXPECT_EQ(0, r.GetSocketAddress().port()); } } @@ -774,6 +790,8 @@ TEST_F(URLRequestTest, FileTest) { EXPECT_EQ(1, d.response_started_count()); EXPECT_FALSE(d.received_data_before_response()); EXPECT_EQ(d.bytes_received(), static_cast<int>(file_size)); + EXPECT_EQ("", r.GetSocketAddress().host()); + EXPECT_EQ(0, r.GetSocketAddress().port()); } } @@ -2373,6 +2391,10 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPDirectoryListing) { EXPECT_EQ(1, d.response_started_count()); EXPECT_FALSE(d.received_data_before_response()); EXPECT_LT(0, d.bytes_received()); + EXPECT_EQ(test_server_.host_port_pair().host(), + r.GetSocketAddress().host()); + EXPECT_EQ(test_server_.host_port_pair().port(), + r.GetSocketAddress().port()); } } @@ -2398,6 +2420,10 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPGetTestAnonymous) { EXPECT_EQ(1, d.response_started_count()); EXPECT_FALSE(d.received_data_before_response()); EXPECT_EQ(d.bytes_received(), static_cast<int>(file_size)); + EXPECT_EQ(test_server_.host_port_pair().host(), + r.GetSocketAddress().host()); + EXPECT_EQ(test_server_.host_port_pair().port(), + r.GetSocketAddress().port()); } } @@ -2422,6 +2448,10 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPGetTest) { file_util::GetFileSize(app_path, &file_size); EXPECT_FALSE(r.is_pending()); + EXPECT_EQ(test_server_.host_port_pair().host(), + r.GetSocketAddress().host()); + EXPECT_EQ(test_server_.host_port_pair().port(), + r.GetSocketAddress().port()); EXPECT_EQ(1, d.response_started_count()); EXPECT_FALSE(d.received_data_before_response()); EXPECT_EQ(d.bytes_received(), static_cast<int>(file_size)); diff --git a/webkit/glue/resource_loader_bridge.h b/webkit/glue/resource_loader_bridge.h index 23ebb35..e12f142 100644 --- a/webkit/glue/resource_loader_bridge.h +++ b/webkit/glue/resource_loader_bridge.h @@ -31,6 +31,7 @@ #include "base/time.h" #include "base/values.h" #include "googleurl/src/gurl.h" +#include "net/base/host_port_pair.h" #include "net/url_request/url_request_status.h" #include "webkit/glue/resource_type.h" @@ -182,6 +183,9 @@ struct ResourceResponseInfo { // transparent proxy). The proxy could be any type of proxy, HTTP or SOCKS. // Note: we cannot tell if a transparent proxy may have been involved. bool was_fetched_via_proxy; + + // Remote address of the socket which fetched this resource. + net::HostPortPair socket_address; }; class ResourceLoaderBridge { diff --git a/webkit/glue/weburlloader_impl.cc b/webkit/glue/weburlloader_impl.cc index d4b5162..e461ca9 100644 --- a/webkit/glue/weburlloader_impl.cc +++ b/webkit/glue/weburlloader_impl.cc @@ -187,6 +187,9 @@ void PopulateURLResponse( response->setWasAlternateProtocolAvailable( info.was_alternate_protocol_available); response->setWasFetchedViaProxy(info.was_fetched_via_proxy); + response->setRemoteIPAddress( + WebString::fromUTF8(info.socket_address.host())); + response->setRemotePort(info.socket_address.port()); response->setConnectionID(info.connection_id); response->setConnectionReused(info.connection_reused); response->setDownloadFilePath(FilePathToWebString(info.download_file_path)); |