[email protected] | 89f8a5cc | 2012-03-05 16:33:51 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
dcheng | 5971627 | 2016-04-09 05:19:08 | [diff] [blame] | 5 | #include "content/browser/devtools/devtools_manager.h" |
| 6 | |
| 7 | #include <memory> |
| 8 | |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 9 | #include "base/guid.h" |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 10 | #include "base/location.h" |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 11 | #include "base/macros.h" |
gab | f64a25e | 2017-05-12 19:42:56 | [diff] [blame] | 12 | #include "base/message_loop/message_loop.h" |
fdoray | e716a90 | 2016-07-05 16:05:49 | [diff] [blame] | 13 | #include "base/run_loop.h" |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 14 | #include "base/single_thread_task_runner.h" |
gab | 30f26df | 2016-05-11 19:37:55 | [diff] [blame] | 15 | #include "base/threading/thread_task_runner_handle.h" |
[email protected] | a43858f | 2013-06-28 15:18:37 | [diff] [blame] | 16 | #include "base/time/time.h" |
kinuko | 647819d | 2014-12-22 09:54:44 | [diff] [blame] | 17 | #include "content/browser/devtools/shared_worker_devtools_manager.h" |
[email protected] | bfaf3605 | 2011-11-16 07:30:23 | [diff] [blame] | 18 | #include "content/common/view_messages.h" |
dgozman | 24bfc91 | 2014-09-29 11:04:18 | [diff] [blame] | 19 | #include "content/public/browser/browser_context.h" |
[email protected] | 87f3c08 | 2011-10-19 18:07:44 | [diff] [blame] | 20 | #include "content/public/browser/content_browser_client.h" |
[email protected] | 98f6611 | 2012-12-25 12:59:36 | [diff] [blame] | 21 | #include "content/public/browser/devtools_agent_host.h" |
[email protected] | cb286af | 2013-03-26 12:46:45 | [diff] [blame] | 22 | #include "content/public/browser/devtools_external_agent_proxy.h" |
| 23 | #include "content/public/browser/devtools_external_agent_proxy_delegate.h" |
[email protected] | 674bc59 | 2011-12-20 23:00:42 | [diff] [blame] | 24 | #include "content/public/browser/web_contents_delegate.h" |
dgozman | 7e41e3ec | 2017-06-12 21:39:05 | [diff] [blame] | 25 | #include "content/public/common/browser_side_navigation_policy.h" |
Arthur Hemery | 7de58aa | 2017-08-30 13:22:23 | [diff] [blame] | 26 | #include "content/public/test/navigation_simulator.h" |
dgozman | 24bfc91 | 2014-09-29 11:04:18 | [diff] [blame] | 27 | #include "content/public/test/test_utils.h" |
[email protected] | c6681f3 | 2012-06-05 14:43:01 | [diff] [blame] | 28 | #include "content/test/test_content_browser_client.h" |
[email protected] | 4bfd461 | 2013-12-05 18:12:48 | [diff] [blame] | 29 | #include "content/test/test_render_view_host.h" |
[email protected] | 4172b08 | 2013-02-25 18:07:34 | [diff] [blame] | 30 | #include "content/test/test_web_contents.h" |
[email protected] | 79ea486 | 2011-02-24 00:46:44 | [diff] [blame] | 31 | #include "testing/gtest/include/gtest/gtest.h" |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 32 | |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 33 | using base::TimeDelta; |
| 34 | |
[email protected] | de551c6 | 2012-10-24 20:50:08 | [diff] [blame] | 35 | namespace content { |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 36 | namespace { |
| 37 | |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 38 | class TestDevToolsClientHost : public DevToolsAgentHostClient { |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 39 | public: |
Ivan Kotenkov | 2c0d2bb3 | 2017-11-01 15:41:28 | [diff] [blame] | 40 | TestDevToolsClientHost() : last_sent_message(nullptr), closed_(false) {} |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 41 | |
dcheng | c2282aa | 2014-10-21 12:07:58 | [diff] [blame] | 42 | ~TestDevToolsClientHost() override { EXPECT_TRUE(closed_); } |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 43 | |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 44 | void Close() { |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 45 | EXPECT_FALSE(closed_); |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 46 | close_counter++; |
pfeldman | fb8e747 | 2016-06-08 21:13:37 | [diff] [blame] | 47 | agent_host_->DetachClient(this); |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 48 | closed_ = true; |
| 49 | } |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 50 | |
Pavel Feldman | a344d93 | 2017-10-31 20:24:52 | [diff] [blame] | 51 | void AgentHostClosed(DevToolsAgentHost* agent_host) override { FAIL(); } |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 52 | |
dcheng | c2282aa | 2014-10-21 12:07:58 | [diff] [blame] | 53 | void DispatchProtocolMessage(DevToolsAgentHost* agent_host, |
| 54 | const std::string& message) override { |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 55 | last_sent_message = &message; |
| 56 | } |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 57 | |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 58 | void InspectAgentHost(DevToolsAgentHost* agent_host) { |
| 59 | agent_host_ = agent_host; |
| 60 | agent_host_->AttachClient(this); |
[email protected] | b3b2607 | 2012-11-02 11:20:51 | [diff] [blame] | 61 | } |
| 62 | |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 63 | DevToolsAgentHost* agent_host() { return agent_host_.get(); } |
| 64 | |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 65 | static void ResetCounters() { |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 66 | close_counter = 0; |
| 67 | } |
| 68 | |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 69 | static int close_counter; |
| 70 | |
[email protected] | 0e12d7d | 2011-12-01 16:21:44 | [diff] [blame] | 71 | const std::string* last_sent_message; |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 72 | |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 73 | private: |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 74 | bool closed_; |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 75 | scoped_refptr<DevToolsAgentHost> agent_host_; |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 76 | |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 77 | DISALLOW_COPY_AND_ASSIGN(TestDevToolsClientHost); |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 78 | }; |
| 79 | |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 80 | int TestDevToolsClientHost::close_counter = 0; |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 81 | |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 82 | |
[email protected] | de551c6 | 2012-10-24 20:50:08 | [diff] [blame] | 83 | class TestWebContentsDelegate : public WebContentsDelegate { |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 84 | public: |
[email protected] | 674bc59 | 2011-12-20 23:00:42 | [diff] [blame] | 85 | TestWebContentsDelegate() : renderer_unresponsive_received_(false) {} |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 86 | |
[email protected] | a026243 | 2012-04-13 15:48:09 | [diff] [blame] | 87 | // Notification that the contents is hung. |
Avi Drissman | 8920def | 2018-01-31 19:53:36 | [diff] [blame] | 88 | void RendererUnresponsive(WebContents* source, |
| 89 | RenderProcessHost* render_process_host) override { |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 90 | renderer_unresponsive_received_ = true; |
| 91 | } |
| 92 | |
| 93 | bool renderer_unresponsive_received() const { |
| 94 | return renderer_unresponsive_received_; |
| 95 | } |
| 96 | |
| 97 | private: |
| 98 | bool renderer_unresponsive_received_; |
| 99 | }; |
| 100 | |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 101 | } // namespace |
| 102 | |
[email protected] | c025738 | 2012-03-12 20:15:34 | [diff] [blame] | 103 | class DevToolsManagerTest : public RenderViewHostImplTestHarness { |
dgozman | 24bfc91 | 2014-09-29 11:04:18 | [diff] [blame] | 104 | public: |
dgozman | 88f570805 | 2015-04-28 16:31:25 | [diff] [blame] | 105 | DevToolsManagerTest() {} |
dgozman | 24bfc91 | 2014-09-29 11:04:18 | [diff] [blame] | 106 | |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 107 | protected: |
dcheng | fa85b15 | 2014-10-28 01:13:42 | [diff] [blame] | 108 | void SetUp() override { |
[email protected] | 46a32b9 | 2012-03-22 13:04:48 | [diff] [blame] | 109 | RenderViewHostImplTestHarness::SetUp(); |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 110 | TestDevToolsClientHost::ResetCounters(); |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 111 | } |
| 112 | }; |
| 113 | |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 114 | TEST_F(DevToolsManagerTest, OpenAndManuallyCloseDevToolsClientHost) { |
[email protected] | 2d92a63 | 2013-03-15 17:12:49 | [diff] [blame] | 115 | scoped_refptr<DevToolsAgentHost> agent( |
[email protected] | b3f957e6 | 2014-08-08 10:09:02 | [diff] [blame] | 116 | DevToolsAgentHost::GetOrCreateFor(web_contents())); |
[email protected] | 94305ee9 | 2013-04-01 14:19:58 | [diff] [blame] | 117 | EXPECT_FALSE(agent->IsAttached()); |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 118 | |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 119 | TestDevToolsClientHost client_host; |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 120 | client_host.InspectAgentHost(agent.get()); |
[email protected] | 94305ee9 | 2013-04-01 14:19:58 | [diff] [blame] | 121 | // Test that the connection is established. |
| 122 | EXPECT_TRUE(agent->IsAttached()); |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 123 | EXPECT_EQ(0, TestDevToolsClientHost::close_counter); |
[email protected] | f85d541 | 2009-03-17 12:05:48 | [diff] [blame] | 124 | |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 125 | client_host.Close(); |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 126 | EXPECT_EQ(1, TestDevToolsClientHost::close_counter); |
[email protected] | 94305ee9 | 2013-04-01 14:19:58 | [diff] [blame] | 127 | EXPECT_FALSE(agent->IsAttached()); |
[email protected] | 7aa27fd | 2009-03-23 10:43:58 | [diff] [blame] | 128 | } |
| 129 | |
[email protected] | a026243 | 2012-04-13 15:48:09 | [diff] [blame] | 130 | TEST_F(DevToolsManagerTest, NoUnresponsiveDialogInInspectedContents) { |
nick | 16b0765 | 2015-04-18 02:35:31 | [diff] [blame] | 131 | const GURL url("http://www.google.com"); |
| 132 | contents()->NavigateAndCommit(url); |
[email protected] | de551c6 | 2012-10-24 20:50:08 | [diff] [blame] | 133 | TestRenderViewHost* inspected_rvh = test_rvh(); |
nick | 16b0765 | 2015-04-18 02:35:31 | [diff] [blame] | 134 | EXPECT_TRUE(inspected_rvh->IsRenderViewLive()); |
[email protected] | 6934a70 | 2011-12-20 00:04:51 | [diff] [blame] | 135 | EXPECT_FALSE(contents()->GetDelegate()); |
[email protected] | 674bc59 | 2011-12-20 23:00:42 | [diff] [blame] | 136 | TestWebContentsDelegate delegate; |
[email protected] | 6934a70 | 2011-12-20 00:04:51 | [diff] [blame] | 137 | contents()->SetDelegate(&delegate); |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 138 | |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 139 | TestDevToolsClientHost client_host; |
[email protected] | b3f957e6 | 2014-08-08 10:09:02 | [diff] [blame] | 140 | scoped_refptr<DevToolsAgentHost> agent_host(DevToolsAgentHost::GetOrCreateFor( |
| 141 | WebContents::FromRenderViewHost(inspected_rvh))); |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 142 | client_host.InspectAgentHost(agent_host.get()); |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 143 | |
| 144 | // Start with a short timeout. |
avi | 3627ecac | 2015-10-16 17:40:43 | [diff] [blame] | 145 | inspected_rvh->GetWidget()->StartHangMonitorTimeout( |
Dave Tapuska | c6146c5 | 2017-12-20 22:48:15 | [diff] [blame] | 146 | TimeDelta::FromMilliseconds(10)); |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 147 | // Wait long enough for first timeout and see if it fired. |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 148 | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
ki.stfu | 80077924 | 2015-10-12 22:46:26 | [diff] [blame] | 149 | FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(), |
[email protected] | dd32b127 | 2013-05-04 14:17:11 | [diff] [blame] | 150 | TimeDelta::FromMilliseconds(10)); |
fdoray | e716a90 | 2016-07-05 16:05:49 | [diff] [blame] | 151 | base::RunLoop().Run(); |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 152 | EXPECT_FALSE(delegate.renderer_unresponsive_received()); |
| 153 | |
| 154 | // Now close devtools and check that the notification is delivered. |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 155 | client_host.Close(); |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 156 | // Start with a short timeout. |
avi | 3627ecac | 2015-10-16 17:40:43 | [diff] [blame] | 157 | inspected_rvh->GetWidget()->StartHangMonitorTimeout( |
Dave Tapuska | c6146c5 | 2017-12-20 22:48:15 | [diff] [blame] | 158 | TimeDelta::FromMilliseconds(10)); |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 159 | // Wait long enough for first timeout and see if it fired. |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 160 | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
ki.stfu | 80077924 | 2015-10-12 22:46:26 | [diff] [blame] | 161 | FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(), |
[email protected] | dd32b127 | 2013-05-04 14:17:11 | [diff] [blame] | 162 | TimeDelta::FromMilliseconds(10)); |
fdoray | e716a90 | 2016-07-05 16:05:49 | [diff] [blame] | 163 | base::RunLoop().Run(); |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 164 | EXPECT_TRUE(delegate.renderer_unresponsive_received()); |
| 165 | |
Ivan Kotenkov | 2c0d2bb3 | 2017-11-01 15:41:28 | [diff] [blame] | 166 | contents()->SetDelegate(nullptr); |
[email protected] | e5fc163 | 2011-08-08 07:51:53 | [diff] [blame] | 167 | } |
[email protected] | bfaf3605 | 2011-11-16 07:30:23 | [diff] [blame] | 168 | |
[email protected] | cb286af | 2013-03-26 12:46:45 | [diff] [blame] | 169 | class TestExternalAgentDelegate: public DevToolsExternalAgentProxyDelegate { |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 170 | public: |
pfeldman | 1062876 | 2016-09-08 07:59:26 | [diff] [blame] | 171 | TestExternalAgentDelegate() { |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 172 | } |
| 173 | ~TestExternalAgentDelegate() override { |
| 174 | expectEvent(1, "Attach"); |
| 175 | expectEvent(1, "Detach"); |
| 176 | expectEvent(0, "SendMessageToBackend.message0"); |
| 177 | expectEvent(1, "SendMessageToBackend.message1"); |
| 178 | expectEvent(2, "SendMessageToBackend.message2"); |
| 179 | } |
| 180 | |
| 181 | private: |
[email protected] | cb286af | 2013-03-26 12:46:45 | [diff] [blame] | 182 | std::map<std::string,int> event_counter_; |
| 183 | |
| 184 | void recordEvent(const std::string& name) { |
| 185 | if (event_counter_.find(name) == event_counter_.end()) |
| 186 | event_counter_[name] = 0; |
| 187 | event_counter_[name] = event_counter_[name] + 1; |
| 188 | } |
| 189 | |
| 190 | void expectEvent(int count, const std::string& name) { |
| 191 | EXPECT_EQ(count, event_counter_[name]); |
| 192 | } |
| 193 | |
dcheng | c2282aa | 2014-10-21 12:07:58 | [diff] [blame] | 194 | void Attach(DevToolsExternalAgentProxy* proxy) override { |
[email protected] | cb286af | 2013-03-26 12:46:45 | [diff] [blame] | 195 | recordEvent("Attach"); |
| 196 | }; |
| 197 | |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 198 | void Detach(DevToolsExternalAgentProxy* proxy) override { |
| 199 | recordEvent("Detach"); |
| 200 | }; |
[email protected] | cb286af | 2013-03-26 12:46:45 | [diff] [blame] | 201 | |
pfeldman | e7d2e41 | 2016-09-23 16:41:51 | [diff] [blame] | 202 | std::string GetType() override { return std::string(); } |
| 203 | std::string GetTitle() override { return std::string(); } |
| 204 | std::string GetDescription() override { return std::string(); } |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 205 | GURL GetURL() override { return GURL(); } |
| 206 | GURL GetFaviconURL() override { return GURL(); } |
pfeldman | e7d2e41 | 2016-09-23 16:41:51 | [diff] [blame] | 207 | std::string GetFrontendURL() override { return std::string(); } |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 208 | bool Activate() override { return false; }; |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 209 | void Reload() override { }; |
| 210 | bool Close() override { return false; }; |
pfeldman | 97088372 | 2017-02-08 06:08:53 | [diff] [blame] | 211 | base::TimeTicks GetLastActivityTime() override { return base::TimeTicks(); } |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 212 | |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 213 | void SendMessageToBackend(DevToolsExternalAgentProxy* proxy, |
| 214 | const std::string& message) override { |
[email protected] | cb286af | 2013-03-26 12:46:45 | [diff] [blame] | 215 | recordEvent(std::string("SendMessageToBackend.") + message); |
| 216 | }; |
| 217 | |
[email protected] | cb286af | 2013-03-26 12:46:45 | [diff] [blame] | 218 | }; |
| 219 | |
| 220 | TEST_F(DevToolsManagerTest, TestExternalProxy) { |
pfeldman | 1062876 | 2016-09-08 07:59:26 | [diff] [blame] | 221 | std::unique_ptr<TestExternalAgentDelegate> delegate( |
| 222 | new TestExternalAgentDelegate()); |
[email protected] | cb286af | 2013-03-26 12:46:45 | [diff] [blame] | 223 | |
[email protected] | 42de6e14 | 2014-05-29 21:02:47 | [diff] [blame] | 224 | scoped_refptr<DevToolsAgentHost> agent_host = |
pfeldman | 1062876 | 2016-09-08 07:59:26 | [diff] [blame] | 225 | DevToolsAgentHost::Forward(base::GenerateGUID(), std::move(delegate)); |
[email protected] | cb286af | 2013-03-26 12:46:45 | [diff] [blame] | 226 | EXPECT_EQ(agent_host, DevToolsAgentHost::GetForId(agent_host->GetId())); |
| 227 | |
[email protected] | d9eb519e | 2014-08-12 12:32:08 | [diff] [blame] | 228 | TestDevToolsClientHost client_host; |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 229 | client_host.InspectAgentHost(agent_host.get()); |
pfeldman | fb8e747 | 2016-06-08 21:13:37 | [diff] [blame] | 230 | agent_host->DispatchProtocolMessage(&client_host, "message1"); |
| 231 | agent_host->DispatchProtocolMessage(&client_host, "message2"); |
| 232 | agent_host->DispatchProtocolMessage(&client_host, "message2"); |
[email protected] | d9eb519e | 2014-08-12 12:32:08 | [diff] [blame] | 233 | |
[email protected] | b50452f | 2014-08-18 12:31:44 | [diff] [blame] | 234 | client_host.Close(); |
[email protected] | cb286af | 2013-03-26 12:46:45 | [diff] [blame] | 235 | } |
| 236 | |
[email protected] | de551c6 | 2012-10-24 20:50:08 | [diff] [blame] | 237 | } // namespace content |