OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/spdy/spdy_session.h" | 5 #include "net/spdy/spdy_session.h" |
6 | 6 |
7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
8 #include "net/base/io_buffer.h" | 8 #include "net/base/io_buffer.h" |
9 #include "net/base/ip_endpoint.h" | 9 #include "net/base/ip_endpoint.h" |
10 #include "net/base/net_log_unittest.h" | 10 #include "net/base/net_log_unittest.h" |
(...skipping 2256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2267 | 2267 |
2268 EXPECT_EQ(kDefaultInitialRecvWindowSize, session->session_recv_window_size_); | 2268 EXPECT_EQ(kDefaultInitialRecvWindowSize, session->session_recv_window_size_); |
2269 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); | 2269 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
2270 | 2270 |
2271 data.RunFor(3); | 2271 data.RunFor(3); |
2272 | 2272 |
2273 EXPECT_EQ(kDefaultInitialRecvWindowSize, session->session_recv_window_size_); | 2273 EXPECT_EQ(kDefaultInitialRecvWindowSize, session->session_recv_window_size_); |
2274 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); | 2274 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
2275 } | 2275 } |
2276 | 2276 |
| 2277 // A delegate that drops any received data. |
| 2278 class DropReceivedDataDelegate : public test::StreamDelegateSendImmediate { |
| 2279 public: |
| 2280 DropReceivedDataDelegate(const scoped_refptr<SpdyStream>& stream, |
| 2281 base::StringPiece data) |
| 2282 : StreamDelegateSendImmediate( |
| 2283 stream, scoped_ptr<SpdyHeaderBlock>(), data) {} |
| 2284 |
| 2285 virtual ~DropReceivedDataDelegate() {} |
| 2286 |
| 2287 // Drop any received data. |
| 2288 virtual int OnDataReceived(scoped_ptr<SpdyBuffer> buffer) OVERRIDE { |
| 2289 return OK; |
| 2290 } |
| 2291 }; |
| 2292 |
| 2293 // Send data back and forth but use a delegate that drops its received |
| 2294 // data. The receive window should still increase to its original |
| 2295 // value, i.e. we shouldn't "leak" receive window bytes. |
| 2296 TEST_F(SpdySessionSpdy3Test, SessionFlowControlNoReceiveLeaks31) { |
| 2297 const char kStreamUrl[] = "http://www.google.com/"; |
| 2298 |
| 2299 session_deps_.enable_spdy_31 = true; |
| 2300 |
| 2301 const int32 msg_data_size = 100; |
| 2302 const std::string msg_data(msg_data_size, 'a'); |
| 2303 |
| 2304 MockConnect connect_data(SYNCHRONOUS, OK); |
| 2305 |
| 2306 scoped_ptr<SpdyFrame> initial_window_update( |
| 2307 ConstructSpdyWindowUpdate( |
| 2308 kSessionFlowControlStreamId, |
| 2309 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize)); |
| 2310 scoped_ptr<SpdyFrame> req( |
| 2311 ConstructSpdyPost(kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0)); |
| 2312 scoped_ptr<SpdyFrame> msg( |
| 2313 ConstructSpdyBodyFrame(1, msg_data.data(), msg_data_size, false)); |
| 2314 MockWrite writes[] = { |
| 2315 CreateMockWrite(*initial_window_update, 0), |
| 2316 CreateMockWrite(*req, 1), |
| 2317 CreateMockWrite(*msg, 3), |
| 2318 }; |
| 2319 |
| 2320 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 2321 scoped_ptr<SpdyFrame> echo( |
| 2322 ConstructSpdyBodyFrame(1, msg_data.data(), msg_data_size, false)); |
| 2323 scoped_ptr<SpdyFrame> window_update( |
| 2324 ConstructSpdyWindowUpdate( |
| 2325 kSessionFlowControlStreamId, msg_data_size)); |
| 2326 MockRead reads[] = { |
| 2327 CreateMockRead(*resp, 2), |
| 2328 CreateMockRead(*echo, 4), |
| 2329 MockRead(ASYNC, 0, 5) // EOF |
| 2330 }; |
| 2331 |
| 2332 // Create SpdySession and SpdyStream and send the request. |
| 2333 DeterministicSocketData data(reads, arraysize(reads), |
| 2334 writes, arraysize(writes)); |
| 2335 data.set_connect_data(connect_data); |
| 2336 session_deps_.host_resolver->set_synchronous_mode(true); |
| 2337 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
| 2338 |
| 2339 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
| 2340 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); |
| 2341 |
| 2342 CreateDeterministicNetworkSession(); |
| 2343 |
| 2344 scoped_refptr<SpdySession> session = CreateInitializedSession(); |
| 2345 |
| 2346 GURL url(kStreamUrl); |
| 2347 scoped_refptr<SpdyStream> stream = |
| 2348 CreateStreamSynchronously(session, url, MEDIUM, BoundNetLog()); |
| 2349 ASSERT_TRUE(stream.get() != NULL); |
| 2350 EXPECT_EQ(0u, stream->stream_id()); |
| 2351 |
| 2352 DropReceivedDataDelegate delegate(stream, msg_data); |
| 2353 stream->SetDelegate(&delegate); |
| 2354 |
| 2355 stream->set_spdy_headers( |
| 2356 ConstructPostHeaderBlock(url.spec(), msg_data_size)); |
| 2357 EXPECT_TRUE(stream->HasUrl()); |
| 2358 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true)); |
| 2359 |
| 2360 EXPECT_EQ(kDefaultInitialRecvWindowSize, session->session_recv_window_size_); |
| 2361 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
| 2362 |
| 2363 data.RunFor(5); |
| 2364 |
| 2365 EXPECT_TRUE(data.at_write_eof()); |
| 2366 EXPECT_TRUE(data.at_read_eof()); |
| 2367 |
| 2368 EXPECT_EQ(kDefaultInitialRecvWindowSize, session->session_recv_window_size_); |
| 2369 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); |
| 2370 |
| 2371 stream->Close(); |
| 2372 |
| 2373 EXPECT_EQ(OK, delegate.WaitForClose()); |
| 2374 |
| 2375 EXPECT_EQ(kDefaultInitialRecvWindowSize, session->session_recv_window_size_); |
| 2376 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); |
| 2377 } |
| 2378 |
2277 // Send data back and forth; the send and receive windows should | 2379 // Send data back and forth; the send and receive windows should |
2278 // change appropriately. | 2380 // change appropriately. |
2279 TEST_F(SpdySessionSpdy3Test, SessionFlowControlEndToEnd31) { | 2381 TEST_F(SpdySessionSpdy3Test, SessionFlowControlEndToEnd31) { |
2280 const char kStreamUrl[] = "http://www.google.com/"; | 2382 const char kStreamUrl[] = "http://www.google.com/"; |
2281 | 2383 |
2282 session_deps_.enable_spdy_31 = true; | 2384 session_deps_.enable_spdy_31 = true; |
2283 | 2385 |
2284 const int32 msg_data_size = 100; | 2386 const int32 msg_data_size = 100; |
2285 const std::string msg_data(msg_data_size, 'a'); | 2387 const std::string msg_data(msg_data_size, 'a'); |
2286 | 2388 |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2377 data.RunFor(1); | 2479 data.RunFor(1); |
2378 | 2480 |
2379 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); | 2481 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); |
2380 EXPECT_EQ(kDefaultInitialRecvWindowSize - msg_data_size, | 2482 EXPECT_EQ(kDefaultInitialRecvWindowSize - msg_data_size, |
2381 session->session_recv_window_size_); | 2483 session->session_recv_window_size_); |
2382 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); | 2484 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
2383 | 2485 |
2384 EXPECT_TRUE(data.at_write_eof()); | 2486 EXPECT_TRUE(data.at_write_eof()); |
2385 EXPECT_TRUE(data.at_read_eof()); | 2487 EXPECT_TRUE(data.at_read_eof()); |
2386 | 2488 |
2387 // Normally done by the delegate, but not by our test delegate. | 2489 EXPECT_EQ(msg_data, delegate.TakeReceivedData()); |
2388 session->IncreaseRecvWindowSize(msg_data_size); | |
2389 | 2490 |
| 2491 // Draining the delegate's read queue should increase our receive |
| 2492 // window. |
2390 EXPECT_EQ(kDefaultInitialRecvWindowSize, session->session_recv_window_size_); | 2493 EXPECT_EQ(kDefaultInitialRecvWindowSize, session->session_recv_window_size_); |
2391 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); | 2494 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); |
2392 | 2495 |
2393 stream->Close(); | 2496 stream->Close(); |
2394 | 2497 |
2395 EXPECT_EQ(OK, delegate.WaitForClose()); | 2498 EXPECT_EQ(OK, delegate.WaitForClose()); |
| 2499 |
| 2500 EXPECT_EQ(kDefaultInitialRecvWindowSize, session->session_recv_window_size_); |
| 2501 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); |
2396 } | 2502 } |
2397 | 2503 |
2398 // Cause a stall by reducing the flow control send window to 0. The | 2504 // Cause a stall by reducing the flow control send window to 0. The |
2399 // stream should resume when that window is then increased. | 2505 // stream should resume when that window is then increased. |
2400 TEST_F(SpdySessionSpdy3Test, ResumeAfterSendWindowSizeIncrease31) { | 2506 TEST_F(SpdySessionSpdy3Test, ResumeAfterSendWindowSizeIncrease31) { |
2401 const char kStreamUrl[] = "http://www.google.com/"; | 2507 const char kStreamUrl[] = "http://www.google.com/"; |
2402 GURL url(kStreamUrl); | 2508 GURL url(kStreamUrl); |
2403 | 2509 |
2404 session_deps_.enable_spdy_31 = true; | 2510 session_deps_.enable_spdy_31 = true; |
2405 session_deps_.host_resolver->set_synchronous_mode(true); | 2511 session_deps_.host_resolver->set_synchronous_mode(true); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2471 | 2577 |
2472 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | 2578 EXPECT_FALSE(stream->send_stalled_by_flow_control()); |
2473 | 2579 |
2474 data.RunFor(3); | 2580 data.RunFor(3); |
2475 | 2581 |
2476 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); | 2582 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); |
2477 | 2583 |
2478 EXPECT_TRUE(delegate.send_headers_completed()); | 2584 EXPECT_TRUE(delegate.send_headers_completed()); |
2479 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); | 2585 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); |
2480 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version")); | 2586 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version")); |
2481 EXPECT_EQ(kBodyDataStringPiece.as_string(), delegate.received_data()); | 2587 EXPECT_EQ(kBodyDataStringPiece.as_string(), delegate.TakeReceivedData()); |
2482 EXPECT_EQ(static_cast<int>(kBodyDataSize), delegate.body_data_sent()); | 2588 EXPECT_EQ(static_cast<int>(kBodyDataSize), delegate.body_data_sent()); |
2483 } | 2589 } |
2484 | 2590 |
2485 // Cause a stall by reducing the flow control send window to 0. The | 2591 // Cause a stall by reducing the flow control send window to 0. The |
2486 // streams should resume in priority order when that window is then | 2592 // streams should resume in priority order when that window is then |
2487 // increased. | 2593 // increased. |
2488 TEST_F(SpdySessionSpdy3Test, ResumeByPriorityAfterSendWindowSizeIncrease31) { | 2594 TEST_F(SpdySessionSpdy3Test, ResumeByPriorityAfterSendWindowSizeIncrease31) { |
2489 const char kStreamUrl[] = "http://www.google.com/"; | 2595 const char kStreamUrl[] = "http://www.google.com/"; |
2490 GURL url(kStreamUrl); | 2596 GURL url(kStreamUrl); |
2491 | 2597 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2607 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | 2713 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
2608 | 2714 |
2609 data.RunFor(3); | 2715 data.RunFor(3); |
2610 | 2716 |
2611 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); | 2717 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
2612 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); | 2718 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
2613 | 2719 |
2614 EXPECT_TRUE(delegate1.send_headers_completed()); | 2720 EXPECT_TRUE(delegate1.send_headers_completed()); |
2615 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); | 2721 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); |
2616 EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version")); | 2722 EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version")); |
2617 EXPECT_EQ(kBodyDataStringPiece.as_string(), delegate1.received_data()); | 2723 EXPECT_EQ(kBodyDataStringPiece.as_string(), delegate1.TakeReceivedData()); |
2618 EXPECT_EQ(static_cast<int>(kBodyDataSize), delegate1.body_data_sent()); | 2724 EXPECT_EQ(static_cast<int>(kBodyDataSize), delegate1.body_data_sent()); |
2619 | 2725 |
2620 EXPECT_TRUE(delegate2.send_headers_completed()); | 2726 EXPECT_TRUE(delegate2.send_headers_completed()); |
2621 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); | 2727 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); |
2622 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); | 2728 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); |
2623 EXPECT_EQ(kBodyDataStringPiece.as_string(), delegate2.received_data()); | 2729 EXPECT_EQ(kBodyDataStringPiece.as_string(), delegate2.TakeReceivedData()); |
2624 EXPECT_EQ(static_cast<int>(kBodyDataSize), delegate2.body_data_sent()); | 2730 EXPECT_EQ(static_cast<int>(kBodyDataSize), delegate2.body_data_sent()); |
2625 } | 2731 } |
2626 | 2732 |
2627 // Delegate that closes a given stream after sending its body. | 2733 // Delegate that closes a given stream after sending its body. |
2628 class StreamClosingDelegate : public test::StreamDelegateWithBody { | 2734 class StreamClosingDelegate : public test::StreamDelegateWithBody { |
2629 public: | 2735 public: |
2630 StreamClosingDelegate(const scoped_refptr<SpdyStream>& stream, | 2736 StreamClosingDelegate(const scoped_refptr<SpdyStream>& stream, |
2631 base::StringPiece data) | 2737 base::StringPiece data) |
2632 : StreamDelegateWithBody(stream, data) {} | 2738 : StreamDelegateWithBody(stream, data) {} |
2633 | 2739 |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2801 | 2907 |
2802 data.RunFor(3); | 2908 data.RunFor(3); |
2803 | 2909 |
2804 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); | 2910 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
2805 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); | 2911 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
2806 EXPECT_EQ(OK, delegate3.WaitForClose()); | 2912 EXPECT_EQ(OK, delegate3.WaitForClose()); |
2807 | 2913 |
2808 EXPECT_TRUE(delegate1.send_headers_completed()); | 2914 EXPECT_TRUE(delegate1.send_headers_completed()); |
2809 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); | 2915 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); |
2810 EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version")); | 2916 EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version")); |
2811 EXPECT_EQ("", delegate1.received_data()); | 2917 EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
2812 EXPECT_EQ(0, delegate1.body_data_sent()); | 2918 EXPECT_EQ(0, delegate1.body_data_sent()); |
2813 | 2919 |
2814 EXPECT_TRUE(delegate2.send_headers_completed()); | 2920 EXPECT_TRUE(delegate2.send_headers_completed()); |
2815 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); | 2921 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); |
2816 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); | 2922 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); |
2817 EXPECT_EQ(kBodyDataStringPiece.as_string(), delegate2.received_data()); | 2923 EXPECT_EQ(kBodyDataStringPiece.as_string(), delegate2.TakeReceivedData()); |
2818 EXPECT_EQ(static_cast<int>(kBodyDataSize), delegate2.body_data_sent()); | 2924 EXPECT_EQ(static_cast<int>(kBodyDataSize), delegate2.body_data_sent()); |
2819 | 2925 |
2820 EXPECT_TRUE(delegate3.send_headers_completed()); | 2926 EXPECT_TRUE(delegate3.send_headers_completed()); |
2821 EXPECT_EQ("200", delegate3.GetResponseHeaderValue(":status")); | 2927 EXPECT_EQ("200", delegate3.GetResponseHeaderValue(":status")); |
2822 EXPECT_EQ("HTTP/1.1", delegate3.GetResponseHeaderValue(":version")); | 2928 EXPECT_EQ("HTTP/1.1", delegate3.GetResponseHeaderValue(":version")); |
2823 EXPECT_EQ("", delegate3.received_data()); | 2929 EXPECT_EQ(std::string(), delegate3.TakeReceivedData()); |
2824 EXPECT_EQ(0, delegate3.body_data_sent()); | 2930 EXPECT_EQ(0, delegate3.body_data_sent()); |
2825 } | 2931 } |
2826 | 2932 |
2827 // Delegate that closes a given session after sending its body. | 2933 // Delegate that closes a given session after sending its body. |
2828 class SessionClosingDelegate : public test::StreamDelegateWithBody { | 2934 class SessionClosingDelegate : public test::StreamDelegateWithBody { |
2829 public: | 2935 public: |
2830 SessionClosingDelegate(const scoped_refptr<SpdyStream>& stream, | 2936 SessionClosingDelegate(const scoped_refptr<SpdyStream>& stream, |
2831 base::StringPiece data) | 2937 base::StringPiece data) |
2832 : StreamDelegateWithBody(stream, data) {} | 2938 : StreamDelegateWithBody(stream, data) {} |
2833 | 2939 |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2962 session = NULL; | 3068 session = NULL; |
2963 | 3069 |
2964 EXPECT_FALSE(spdy_session_pool_->HasSession(pair_)); | 3070 EXPECT_FALSE(spdy_session_pool_->HasSession(pair_)); |
2965 | 3071 |
2966 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); | 3072 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
2967 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); | 3073 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
2968 | 3074 |
2969 EXPECT_TRUE(delegate1.send_headers_completed()); | 3075 EXPECT_TRUE(delegate1.send_headers_completed()); |
2970 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); | 3076 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); |
2971 EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version")); | 3077 EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version")); |
2972 EXPECT_EQ("", delegate1.received_data()); | 3078 EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
2973 EXPECT_EQ(0, delegate1.body_data_sent()); | 3079 EXPECT_EQ(0, delegate1.body_data_sent()); |
2974 | 3080 |
2975 EXPECT_TRUE(delegate2.send_headers_completed()); | 3081 EXPECT_TRUE(delegate2.send_headers_completed()); |
2976 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); | 3082 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); |
2977 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); | 3083 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); |
2978 EXPECT_EQ("", delegate2.received_data()); | 3084 EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); |
2979 EXPECT_EQ(0, delegate2.body_data_sent()); | 3085 EXPECT_EQ(0, delegate2.body_data_sent()); |
2980 } | 3086 } |
2981 | 3087 |
2982 } // namespace net | 3088 } // namespace net |
OLD | NEW |