| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/socket/socks_client_socket.h" | 5 #include "net/socket/socks_client_socket.h" |
| 6 | 6 |
| 7 #include "net/base/address_list.h" | 7 #include "net/base/address_list.h" |
| 8 #include "net/base/net_log.h" | 8 #include "net/base/net_log.h" |
| 9 #include "net/base/net_log_unittest.h" | 9 #include "net/base/net_log_unittest.h" |
| 10 #include "net/base/mock_host_resolver.h" | 10 #include "net/base/mock_host_resolver.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 MockWrite writes[], size_t writes_count, | 31 MockWrite writes[], size_t writes_count, |
| 32 HostResolver* host_resolver, | 32 HostResolver* host_resolver, |
| 33 const std::string& hostname, int port, | 33 const std::string& hostname, int port, |
| 34 NetLog* net_log); | 34 NetLog* net_log); |
| 35 virtual void SetUp(); | 35 virtual void SetUp(); |
| 36 | 36 |
| 37 protected: | 37 protected: |
| 38 scoped_ptr<SOCKSClientSocket> user_sock_; | 38 scoped_ptr<SOCKSClientSocket> user_sock_; |
| 39 AddressList address_list_; | 39 AddressList address_list_; |
| 40 StreamSocket* tcp_sock_; | 40 StreamSocket* tcp_sock_; |
| 41 TestOldCompletionCallback callback_; | 41 TestCompletionCallback callback_; |
| 42 scoped_ptr<MockHostResolver> host_resolver_; | 42 scoped_ptr<MockHostResolver> host_resolver_; |
| 43 scoped_ptr<SocketDataProvider> data_; | 43 scoped_ptr<SocketDataProvider> data_; |
| 44 }; | 44 }; |
| 45 | 45 |
| 46 SOCKSClientSocketTest::SOCKSClientSocketTest() | 46 SOCKSClientSocketTest::SOCKSClientSocketTest() |
| 47 : host_resolver_(new MockHostResolver) { | 47 : host_resolver_(new MockHostResolver) { |
| 48 } | 48 } |
| 49 | 49 |
| 50 // Set up platform before every test case | 50 // Set up platform before every test case |
| 51 void SOCKSClientSocketTest::SetUp() { | 51 void SOCKSClientSocketTest::SetUp() { |
| 52 PlatformTest::SetUp(); | 52 PlatformTest::SetUp(); |
| 53 } | 53 } |
| 54 | 54 |
| 55 SOCKSClientSocket* SOCKSClientSocketTest::BuildMockSocket( | 55 SOCKSClientSocket* SOCKSClientSocketTest::BuildMockSocket( |
| 56 MockRead reads[], | 56 MockRead reads[], |
| 57 size_t reads_count, | 57 size_t reads_count, |
| 58 MockWrite writes[], | 58 MockWrite writes[], |
| 59 size_t writes_count, | 59 size_t writes_count, |
| 60 HostResolver* host_resolver, | 60 HostResolver* host_resolver, |
| 61 const std::string& hostname, | 61 const std::string& hostname, |
| 62 int port, | 62 int port, |
| 63 NetLog* net_log) { | 63 NetLog* net_log) { |
| 64 | 64 |
| 65 TestOldCompletionCallback callback; | 65 TestCompletionCallback callback; |
| 66 data_.reset(new StaticSocketDataProvider(reads, reads_count, | 66 data_.reset(new StaticSocketDataProvider(reads, reads_count, |
| 67 writes, writes_count)); | 67 writes, writes_count)); |
| 68 tcp_sock_ = new MockTCPClientSocket(address_list_, net_log, data_.get()); | 68 tcp_sock_ = new MockTCPClientSocket(address_list_, net_log, data_.get()); |
| 69 | 69 |
| 70 int rv = tcp_sock_->Connect(&callback); | 70 int rv = tcp_sock_->Connect(callback.callback()); |
| 71 EXPECT_EQ(ERR_IO_PENDING, rv); | 71 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 72 rv = callback.WaitForResult(); | 72 rv = callback.WaitForResult(); |
| 73 EXPECT_EQ(OK, rv); | 73 EXPECT_EQ(OK, rv); |
| 74 EXPECT_TRUE(tcp_sock_->IsConnected()); | 74 EXPECT_TRUE(tcp_sock_->IsConnected()); |
| 75 | 75 |
| 76 return new SOCKSClientSocket(tcp_sock_, | 76 return new SOCKSClientSocket(tcp_sock_, |
| 77 HostResolver::RequestInfo(HostPortPair(hostname, port)), | 77 HostResolver::RequestInfo(HostPortPair(hostname, port)), |
| 78 host_resolver); | 78 host_resolver); |
| 79 } | 79 } |
| 80 | 80 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), | 137 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), |
| 138 data_writes, arraysize(data_writes), | 138 data_writes, arraysize(data_writes), |
| 139 host_resolver_.get(), | 139 host_resolver_.get(), |
| 140 "localhost", 80, | 140 "localhost", 80, |
| 141 &log)); | 141 &log)); |
| 142 | 142 |
| 143 // At this state the TCP connection is completed but not the SOCKS handshake. | 143 // At this state the TCP connection is completed but not the SOCKS handshake. |
| 144 EXPECT_TRUE(tcp_sock_->IsConnected()); | 144 EXPECT_TRUE(tcp_sock_->IsConnected()); |
| 145 EXPECT_FALSE(user_sock_->IsConnected()); | 145 EXPECT_FALSE(user_sock_->IsConnected()); |
| 146 | 146 |
| 147 int rv = user_sock_->Connect(&callback_); | 147 int rv = user_sock_->Connect(callback_.callback()); |
| 148 EXPECT_EQ(ERR_IO_PENDING, rv); | 148 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 149 | 149 |
| 150 net::CapturingNetLog::EntryList entries; | 150 net::CapturingNetLog::EntryList entries; |
| 151 log.GetEntries(&entries); | 151 log.GetEntries(&entries); |
| 152 EXPECT_TRUE( | 152 EXPECT_TRUE( |
| 153 LogContainsBeginEvent(entries, 0, NetLog::TYPE_SOCKS_CONNECT)); | 153 LogContainsBeginEvent(entries, 0, NetLog::TYPE_SOCKS_CONNECT)); |
| 154 EXPECT_FALSE(user_sock_->IsConnected()); | 154 EXPECT_FALSE(user_sock_->IsConnected()); |
| 155 | 155 |
| 156 rv = callback_.WaitForResult(); | 156 rv = callback_.WaitForResult(); |
| 157 EXPECT_EQ(OK, rv); | 157 EXPECT_EQ(OK, rv); |
| 158 EXPECT_TRUE(user_sock_->IsConnected()); | 158 EXPECT_TRUE(user_sock_->IsConnected()); |
| 159 log.GetEntries(&entries); | 159 log.GetEntries(&entries); |
| 160 EXPECT_TRUE(LogContainsEndEvent( | 160 EXPECT_TRUE(LogContainsEndEvent( |
| 161 entries, -1, NetLog::TYPE_SOCKS_CONNECT)); | 161 entries, -1, NetLog::TYPE_SOCKS_CONNECT)); |
| 162 | 162 |
| 163 scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size())); | 163 scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size())); |
| 164 memcpy(buffer->data(), payload_write.data(), payload_write.size()); | 164 memcpy(buffer->data(), payload_write.data(), payload_write.size()); |
| 165 rv = user_sock_->Write(buffer, payload_write.size(), &callback_); | 165 rv = user_sock_->Write(buffer, payload_write.size(), callback_.callback()); |
| 166 EXPECT_EQ(ERR_IO_PENDING, rv); | 166 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 167 rv = callback_.WaitForResult(); | 167 rv = callback_.WaitForResult(); |
| 168 EXPECT_EQ(static_cast<int>(payload_write.size()), rv); | 168 EXPECT_EQ(static_cast<int>(payload_write.size()), rv); |
| 169 | 169 |
| 170 buffer = new IOBuffer(payload_read.size()); | 170 buffer = new IOBuffer(payload_read.size()); |
| 171 rv = user_sock_->Read(buffer, payload_read.size(), &callback_); | 171 rv = user_sock_->Read(buffer, payload_read.size(), callback_.callback()); |
| 172 EXPECT_EQ(ERR_IO_PENDING, rv); | 172 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 173 rv = callback_.WaitForResult(); | 173 rv = callback_.WaitForResult(); |
| 174 EXPECT_EQ(static_cast<int>(payload_read.size()), rv); | 174 EXPECT_EQ(static_cast<int>(payload_read.size()), rv); |
| 175 EXPECT_EQ(payload_read, std::string(buffer->data(), payload_read.size())); | 175 EXPECT_EQ(payload_read, std::string(buffer->data(), payload_read.size())); |
| 176 | 176 |
| 177 user_sock_->Disconnect(); | 177 user_sock_->Disconnect(); |
| 178 EXPECT_FALSE(tcp_sock_->IsConnected()); | 178 EXPECT_FALSE(tcp_sock_->IsConnected()); |
| 179 EXPECT_FALSE(user_sock_->IsConnected()); | 179 EXPECT_FALSE(user_sock_->IsConnected()); |
| 180 } | 180 } |
| 181 | 181 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 206 MockRead data_reads[] = { | 206 MockRead data_reads[] = { |
| 207 MockRead(false, tests[i].fail_reply, arraysize(tests[i].fail_reply)) }; | 207 MockRead(false, tests[i].fail_reply, arraysize(tests[i].fail_reply)) }; |
| 208 CapturingNetLog log(CapturingNetLog::kUnbounded); | 208 CapturingNetLog log(CapturingNetLog::kUnbounded); |
| 209 | 209 |
| 210 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), | 210 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), |
| 211 data_writes, arraysize(data_writes), | 211 data_writes, arraysize(data_writes), |
| 212 host_resolver_.get(), | 212 host_resolver_.get(), |
| 213 "localhost", 80, | 213 "localhost", 80, |
| 214 &log)); | 214 &log)); |
| 215 | 215 |
| 216 int rv = user_sock_->Connect(&callback_); | 216 int rv = user_sock_->Connect(callback_.callback()); |
| 217 EXPECT_EQ(ERR_IO_PENDING, rv); | 217 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 218 | 218 |
| 219 net::CapturingNetLog::EntryList entries; | 219 net::CapturingNetLog::EntryList entries; |
| 220 log.GetEntries(&entries); | 220 log.GetEntries(&entries); |
| 221 EXPECT_TRUE(LogContainsBeginEvent( | 221 EXPECT_TRUE(LogContainsBeginEvent( |
| 222 entries, 0, NetLog::TYPE_SOCKS_CONNECT)); | 222 entries, 0, NetLog::TYPE_SOCKS_CONNECT)); |
| 223 | 223 |
| 224 rv = callback_.WaitForResult(); | 224 rv = callback_.WaitForResult(); |
| 225 EXPECT_EQ(tests[i].fail_code, rv); | 225 EXPECT_EQ(tests[i].fail_code, rv); |
| 226 EXPECT_FALSE(user_sock_->IsConnected()); | 226 EXPECT_FALSE(user_sock_->IsConnected()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 243 MockRead(true, kSOCKSPartialReply1, arraysize(kSOCKSPartialReply1)), | 243 MockRead(true, kSOCKSPartialReply1, arraysize(kSOCKSPartialReply1)), |
| 244 MockRead(true, kSOCKSPartialReply2, arraysize(kSOCKSPartialReply2)) }; | 244 MockRead(true, kSOCKSPartialReply2, arraysize(kSOCKSPartialReply2)) }; |
| 245 CapturingNetLog log(CapturingNetLog::kUnbounded); | 245 CapturingNetLog log(CapturingNetLog::kUnbounded); |
| 246 | 246 |
| 247 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), | 247 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), |
| 248 data_writes, arraysize(data_writes), | 248 data_writes, arraysize(data_writes), |
| 249 host_resolver_.get(), | 249 host_resolver_.get(), |
| 250 "localhost", 80, | 250 "localhost", 80, |
| 251 &log)); | 251 &log)); |
| 252 | 252 |
| 253 int rv = user_sock_->Connect(&callback_); | 253 int rv = user_sock_->Connect(callback_.callback()); |
| 254 EXPECT_EQ(ERR_IO_PENDING, rv); | 254 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 255 net::CapturingNetLog::EntryList entries; | 255 net::CapturingNetLog::EntryList entries; |
| 256 log.GetEntries(&entries); | 256 log.GetEntries(&entries); |
| 257 EXPECT_TRUE(LogContainsBeginEvent( | 257 EXPECT_TRUE(LogContainsBeginEvent( |
| 258 entries, 0, NetLog::TYPE_SOCKS_CONNECT)); | 258 entries, 0, NetLog::TYPE_SOCKS_CONNECT)); |
| 259 | 259 |
| 260 rv = callback_.WaitForResult(); | 260 rv = callback_.WaitForResult(); |
| 261 EXPECT_EQ(OK, rv); | 261 EXPECT_EQ(OK, rv); |
| 262 EXPECT_TRUE(user_sock_->IsConnected()); | 262 EXPECT_TRUE(user_sock_->IsConnected()); |
| 263 log.GetEntries(&entries); | 263 log.GetEntries(&entries); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 281 MockRead data_reads[] = { | 281 MockRead data_reads[] = { |
| 282 MockRead(true, kSOCKSOkReply, arraysize(kSOCKSOkReply)) }; | 282 MockRead(true, kSOCKSOkReply, arraysize(kSOCKSOkReply)) }; |
| 283 CapturingNetLog log(CapturingNetLog::kUnbounded); | 283 CapturingNetLog log(CapturingNetLog::kUnbounded); |
| 284 | 284 |
| 285 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), | 285 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), |
| 286 data_writes, arraysize(data_writes), | 286 data_writes, arraysize(data_writes), |
| 287 host_resolver_.get(), | 287 host_resolver_.get(), |
| 288 "localhost", 80, | 288 "localhost", 80, |
| 289 &log)); | 289 &log)); |
| 290 | 290 |
| 291 int rv = user_sock_->Connect(&callback_); | 291 int rv = user_sock_->Connect(callback_.callback()); |
| 292 EXPECT_EQ(ERR_IO_PENDING, rv); | 292 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 293 net::CapturingNetLog::EntryList entries; | 293 net::CapturingNetLog::EntryList entries; |
| 294 log.GetEntries(&entries); | 294 log.GetEntries(&entries); |
| 295 EXPECT_TRUE(LogContainsBeginEvent( | 295 EXPECT_TRUE(LogContainsBeginEvent( |
| 296 entries, 0, NetLog::TYPE_SOCKS_CONNECT)); | 296 entries, 0, NetLog::TYPE_SOCKS_CONNECT)); |
| 297 | 297 |
| 298 rv = callback_.WaitForResult(); | 298 rv = callback_.WaitForResult(); |
| 299 EXPECT_EQ(OK, rv); | 299 EXPECT_EQ(OK, rv); |
| 300 EXPECT_TRUE(user_sock_->IsConnected()); | 300 EXPECT_TRUE(user_sock_->IsConnected()); |
| 301 log.GetEntries(&entries); | 301 log.GetEntries(&entries); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 313 // close connection unexpectedly | 313 // close connection unexpectedly |
| 314 MockRead(false, 0) }; | 314 MockRead(false, 0) }; |
| 315 CapturingNetLog log(CapturingNetLog::kUnbounded); | 315 CapturingNetLog log(CapturingNetLog::kUnbounded); |
| 316 | 316 |
| 317 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), | 317 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), |
| 318 data_writes, arraysize(data_writes), | 318 data_writes, arraysize(data_writes), |
| 319 host_resolver_.get(), | 319 host_resolver_.get(), |
| 320 "localhost", 80, | 320 "localhost", 80, |
| 321 &log)); | 321 &log)); |
| 322 | 322 |
| 323 int rv = user_sock_->Connect(&callback_); | 323 int rv = user_sock_->Connect(callback_.callback()); |
| 324 EXPECT_EQ(ERR_IO_PENDING, rv); | 324 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 325 net::CapturingNetLog::EntryList entries; | 325 net::CapturingNetLog::EntryList entries; |
| 326 log.GetEntries(&entries); | 326 log.GetEntries(&entries); |
| 327 EXPECT_TRUE(LogContainsBeginEvent( | 327 EXPECT_TRUE(LogContainsBeginEvent( |
| 328 entries, 0, NetLog::TYPE_SOCKS_CONNECT)); | 328 entries, 0, NetLog::TYPE_SOCKS_CONNECT)); |
| 329 | 329 |
| 330 rv = callback_.WaitForResult(); | 330 rv = callback_.WaitForResult(); |
| 331 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); | 331 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); |
| 332 EXPECT_FALSE(user_sock_->IsConnected()); | 332 EXPECT_FALSE(user_sock_->IsConnected()); |
| 333 log.GetEntries(&entries); | 333 log.GetEntries(&entries); |
| 334 EXPECT_TRUE(LogContainsEndEvent( | 334 EXPECT_TRUE(LogContainsEndEvent( |
| 335 entries, -1, NetLog::TYPE_SOCKS_CONNECT)); | 335 entries, -1, NetLog::TYPE_SOCKS_CONNECT)); |
| 336 } | 336 } |
| 337 | 337 |
| 338 // Tries to connect to an unknown hostname. Should fail rather than | 338 // Tries to connect to an unknown hostname. Should fail rather than |
| 339 // falling back to SOCKS4a. | 339 // falling back to SOCKS4a. |
| 340 TEST_F(SOCKSClientSocketTest, FailedDNS) { | 340 TEST_F(SOCKSClientSocketTest, FailedDNS) { |
| 341 const char hostname[] = "unresolved.ipv4.address"; | 341 const char hostname[] = "unresolved.ipv4.address"; |
| 342 | 342 |
| 343 host_resolver_->rules()->AddSimulatedFailure(hostname); | 343 host_resolver_->rules()->AddSimulatedFailure(hostname); |
| 344 | 344 |
| 345 CapturingNetLog log(CapturingNetLog::kUnbounded); | 345 CapturingNetLog log(CapturingNetLog::kUnbounded); |
| 346 | 346 |
| 347 user_sock_.reset(BuildMockSocket(NULL, 0, | 347 user_sock_.reset(BuildMockSocket(NULL, 0, |
| 348 NULL, 0, | 348 NULL, 0, |
| 349 host_resolver_.get(), | 349 host_resolver_.get(), |
| 350 hostname, 80, | 350 hostname, 80, |
| 351 &log)); | 351 &log)); |
| 352 | 352 |
| 353 int rv = user_sock_->Connect(&callback_); | 353 int rv = user_sock_->Connect(callback_.callback()); |
| 354 EXPECT_EQ(ERR_IO_PENDING, rv); | 354 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 355 net::CapturingNetLog::EntryList entries; | 355 net::CapturingNetLog::EntryList entries; |
| 356 log.GetEntries(&entries); | 356 log.GetEntries(&entries); |
| 357 EXPECT_TRUE(LogContainsBeginEvent( | 357 EXPECT_TRUE(LogContainsBeginEvent( |
| 358 entries, 0, NetLog::TYPE_SOCKS_CONNECT)); | 358 entries, 0, NetLog::TYPE_SOCKS_CONNECT)); |
| 359 | 359 |
| 360 rv = callback_.WaitForResult(); | 360 rv = callback_.WaitForResult(); |
| 361 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv); | 361 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv); |
| 362 EXPECT_FALSE(user_sock_->IsConnected()); | 362 EXPECT_FALSE(user_sock_->IsConnected()); |
| 363 log.GetEntries(&entries); | 363 log.GetEntries(&entries); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 375 MockWrite data_writes[] = { MockWrite(false, "", 0) }; | 375 MockWrite data_writes[] = { MockWrite(false, "", 0) }; |
| 376 MockRead data_reads[] = { MockRead(false, "", 0) }; | 376 MockRead data_reads[] = { MockRead(false, "", 0) }; |
| 377 | 377 |
| 378 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), | 378 user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads), |
| 379 data_writes, arraysize(data_writes), | 379 data_writes, arraysize(data_writes), |
| 380 hanging_resolver.get(), | 380 hanging_resolver.get(), |
| 381 "foo", 80, | 381 "foo", 80, |
| 382 NULL)); | 382 NULL)); |
| 383 | 383 |
| 384 // Start connecting (will get stuck waiting for the host to resolve). | 384 // Start connecting (will get stuck waiting for the host to resolve). |
| 385 int rv = user_sock_->Connect(&callback_); | 385 int rv = user_sock_->Connect(callback_.callback()); |
| 386 EXPECT_EQ(ERR_IO_PENDING, rv); | 386 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 387 | 387 |
| 388 EXPECT_FALSE(user_sock_->IsConnected()); | 388 EXPECT_FALSE(user_sock_->IsConnected()); |
| 389 EXPECT_FALSE(user_sock_->IsConnectedAndIdle()); | 389 EXPECT_FALSE(user_sock_->IsConnectedAndIdle()); |
| 390 | 390 |
| 391 // The host resolver should have received the resolve request. | 391 // The host resolver should have received the resolve request. |
| 392 EXPECT_TRUE(hanging_resolver->HasOutstandingRequest()); | 392 EXPECT_TRUE(hanging_resolver->HasOutstandingRequest()); |
| 393 | 393 |
| 394 // Disconnect the SOCKS socket -- this should cancel the outstanding resolve. | 394 // Disconnect the SOCKS socket -- this should cancel the outstanding resolve. |
| 395 user_sock_->Disconnect(); | 395 user_sock_->Disconnect(); |
| 396 | 396 |
| 397 EXPECT_FALSE(hanging_resolver->HasOutstandingRequest()); | 397 EXPECT_FALSE(hanging_resolver->HasOutstandingRequest()); |
| 398 | 398 |
| 399 EXPECT_FALSE(user_sock_->IsConnected()); | 399 EXPECT_FALSE(user_sock_->IsConnected()); |
| 400 EXPECT_FALSE(user_sock_->IsConnectedAndIdle()); | 400 EXPECT_FALSE(user_sock_->IsConnectedAndIdle()); |
| 401 } | 401 } |
| 402 | 402 |
| 403 } // namespace net | 403 } // namespace net |
| OLD | NEW |