| 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/http/http_stream_factory_impl.h" | 5 #include "net/http/http_stream_factory_impl.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
| 13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 14 #include "net/base/port_util.h" | 14 #include "net/base/port_util.h" |
| 15 #include "net/base/test_completion_callback.h" | 15 #include "net/base/test_completion_callback.h" |
| 16 #include "net/cert/mock_cert_verifier.h" | 16 #include "net/cert/mock_cert_verifier.h" |
| 17 #include "net/dns/mock_host_resolver.h" | 17 #include "net/dns/mock_host_resolver.h" |
| 18 #include "net/http/bidirectional_stream_job.h" |
| 18 #include "net/http/http_auth_handler_factory.h" | 19 #include "net/http/http_auth_handler_factory.h" |
| 19 #include "net/http/http_network_session.h" | 20 #include "net/http/http_network_session.h" |
| 20 #include "net/http/http_network_session_peer.h" | 21 #include "net/http/http_network_session_peer.h" |
| 21 #include "net/http/http_network_transaction.h" | 22 #include "net/http/http_network_transaction.h" |
| 22 #include "net/http/http_request_info.h" | 23 #include "net/http/http_request_info.h" |
| 23 #include "net/http/http_server_properties.h" | 24 #include "net/http/http_server_properties.h" |
| 24 #include "net/http/http_server_properties_impl.h" | 25 #include "net/http/http_server_properties_impl.h" |
| 25 #include "net/http/http_stream.h" | 26 #include "net/http/http_stream.h" |
| 26 #include "net/http/transport_security_state.h" | 27 #include "net/http/transport_security_state.h" |
| 27 #include "net/log/net_log.h" | 28 #include "net/log/net_log.h" |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 return scoped_ptr<WebSocketStream>(); | 106 return scoped_ptr<WebSocketStream>(); |
| 106 } | 107 } |
| 107 | 108 |
| 108 private: | 109 private: |
| 109 const StreamType type_; | 110 const StreamType type_; |
| 110 }; | 111 }; |
| 111 | 112 |
| 112 // HttpStreamFactoryImpl subclass that can wait until a preconnect is complete. | 113 // HttpStreamFactoryImpl subclass that can wait until a preconnect is complete. |
| 113 class MockHttpStreamFactoryImplForPreconnect : public HttpStreamFactoryImpl { | 114 class MockHttpStreamFactoryImplForPreconnect : public HttpStreamFactoryImpl { |
| 114 public: | 115 public: |
| 115 MockHttpStreamFactoryImplForPreconnect(HttpNetworkSession* session, | 116 MockHttpStreamFactoryImplForPreconnect(HttpNetworkSession* session) |
| 116 bool for_websockets) | 117 : HttpStreamFactoryImpl(session, false), |
| 117 : HttpStreamFactoryImpl(session, for_websockets), | |
| 118 preconnect_done_(false), | 118 preconnect_done_(false), |
| 119 waiting_for_preconnect_(false) {} | 119 waiting_for_preconnect_(false) {} |
| 120 | 120 |
| 121 void WaitForPreconnects() { | 121 void WaitForPreconnects() { |
| 122 while (!preconnect_done_) { | 122 while (!preconnect_done_) { |
| 123 waiting_for_preconnect_ = true; | 123 waiting_for_preconnect_ = true; |
| 124 base::MessageLoop::current()->Run(); | 124 base::MessageLoop::current()->Run(); |
| 125 waiting_for_preconnect_ = false; | 125 waiting_for_preconnect_ = false; |
| 126 } | 126 } |
| 127 } | 127 } |
| 128 | 128 |
| 129 private: | 129 private: |
| 130 // HttpStreamFactoryImpl methods. | 130 // HttpStreamFactoryImpl methods. |
| 131 void OnPreconnectsCompleteInternal() override { | 131 void OnPreconnectsCompleteInternal() override { |
| 132 preconnect_done_ = true; | 132 preconnect_done_ = true; |
| 133 if (waiting_for_preconnect_) | 133 if (waiting_for_preconnect_) |
| 134 base::MessageLoop::current()->QuitWhenIdle(); | 134 base::MessageLoop::current()->QuitWhenIdle(); |
| 135 } | 135 } |
| 136 | 136 |
| 137 bool preconnect_done_; | 137 bool preconnect_done_; |
| 138 bool waiting_for_preconnect_; | 138 bool waiting_for_preconnect_; |
| 139 }; | 139 }; |
| 140 | 140 |
| 141 class StreamRequestWaiter : public HttpStreamRequest::Delegate { | 141 class StreamRequestWaiter : public HttpStreamRequest::Delegate { |
| 142 public: | 142 public: |
| 143 StreamRequestWaiter() | 143 StreamRequestWaiter() |
| 144 : waiting_for_stream_(false), | 144 : waiting_for_stream_(false), stream_done_(false), error_status_(OK) {} |
| 145 stream_done_(false) {} | |
| 146 | 145 |
| 147 // HttpStreamRequest::Delegate | 146 // HttpStreamRequest::Delegate |
| 148 | 147 |
| 149 void OnStreamReady(const SSLConfig& used_ssl_config, | 148 void OnStreamReady(const SSLConfig& used_ssl_config, |
| 150 const ProxyInfo& used_proxy_info, | 149 const ProxyInfo& used_proxy_info, |
| 151 HttpStream* stream) override { | 150 HttpStream* stream) override { |
| 152 stream_done_ = true; | 151 stream_done_ = true; |
| 153 if (waiting_for_stream_) | 152 if (waiting_for_stream_) |
| 154 base::MessageLoop::current()->QuitWhenIdle(); | 153 base::MessageLoop::current()->QuitWhenIdle(); |
| 155 stream_.reset(stream); | 154 stream_.reset(stream); |
| 156 used_ssl_config_ = used_ssl_config; | 155 used_ssl_config_ = used_ssl_config; |
| 157 used_proxy_info_ = used_proxy_info; | 156 used_proxy_info_ = used_proxy_info; |
| 158 } | 157 } |
| 159 | 158 |
| 160 void OnWebSocketHandshakeStreamReady( | 159 void OnWebSocketHandshakeStreamReady( |
| 161 const SSLConfig& used_ssl_config, | 160 const SSLConfig& used_ssl_config, |
| 162 const ProxyInfo& used_proxy_info, | 161 const ProxyInfo& used_proxy_info, |
| 163 WebSocketHandshakeStreamBase* stream) override { | 162 WebSocketHandshakeStreamBase* stream) override { |
| 164 stream_done_ = true; | 163 stream_done_ = true; |
| 165 if (waiting_for_stream_) | 164 if (waiting_for_stream_) |
| 166 base::MessageLoop::current()->QuitWhenIdle(); | 165 base::MessageLoop::current()->QuitWhenIdle(); |
| 167 websocket_stream_.reset(stream); | 166 websocket_stream_.reset(stream); |
| 168 used_ssl_config_ = used_ssl_config; | 167 used_ssl_config_ = used_ssl_config; |
| 169 used_proxy_info_ = used_proxy_info; | 168 used_proxy_info_ = used_proxy_info; |
| 170 } | 169 } |
| 171 | 170 |
| 171 void OnBidirectionalStreamJobReady(const SSLConfig& used_ssl_config, |
| 172 const ProxyInfo& used_proxy_info, |
| 173 BidirectionalStreamJob* stream) override { |
| 174 stream_done_ = true; |
| 175 if (waiting_for_stream_) |
| 176 base::MessageLoop::current()->QuitWhenIdle(); |
| 177 bidirectional_stream_job_.reset(stream); |
| 178 used_ssl_config_ = used_ssl_config; |
| 179 used_proxy_info_ = used_proxy_info; |
| 180 } |
| 181 |
| 172 void OnStreamFailed(int status, | 182 void OnStreamFailed(int status, |
| 173 const SSLConfig& used_ssl_config, | 183 const SSLConfig& used_ssl_config, |
| 174 SSLFailureState ssl_failure_state) override {} | 184 SSLFailureState ssl_failure_state) override { |
| 185 stream_done_ = true; |
| 186 if (waiting_for_stream_) |
| 187 base::MessageLoop::current()->QuitWhenIdle(); |
| 188 used_ssl_config_ = used_ssl_config; |
| 189 error_status_ = status; |
| 190 } |
| 175 | 191 |
| 176 void OnCertificateError(int status, | 192 void OnCertificateError(int status, |
| 177 const SSLConfig& used_ssl_config, | 193 const SSLConfig& used_ssl_config, |
| 178 const SSLInfo& ssl_info) override {} | 194 const SSLInfo& ssl_info) override {} |
| 179 | 195 |
| 180 void OnNeedsProxyAuth(const HttpResponseInfo& proxy_response, | 196 void OnNeedsProxyAuth(const HttpResponseInfo& proxy_response, |
| 181 const SSLConfig& used_ssl_config, | 197 const SSLConfig& used_ssl_config, |
| 182 const ProxyInfo& used_proxy_info, | 198 const ProxyInfo& used_proxy_info, |
| 183 HttpAuthController* auth_controller) override {} | 199 HttpAuthController* auth_controller) override {} |
| 184 | 200 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 209 } | 225 } |
| 210 | 226 |
| 211 HttpStream* stream() { | 227 HttpStream* stream() { |
| 212 return stream_.get(); | 228 return stream_.get(); |
| 213 } | 229 } |
| 214 | 230 |
| 215 MockWebSocketHandshakeStream* websocket_stream() { | 231 MockWebSocketHandshakeStream* websocket_stream() { |
| 216 return static_cast<MockWebSocketHandshakeStream*>(websocket_stream_.get()); | 232 return static_cast<MockWebSocketHandshakeStream*>(websocket_stream_.get()); |
| 217 } | 233 } |
| 218 | 234 |
| 235 BidirectionalStreamJob* bidirectional_stream_job() { |
| 236 return bidirectional_stream_job_.get(); |
| 237 } |
| 238 |
| 219 bool stream_done() const { return stream_done_; } | 239 bool stream_done() const { return stream_done_; } |
| 240 int error_status() const { return error_status_; } |
| 220 | 241 |
| 221 private: | 242 private: |
| 222 bool waiting_for_stream_; | 243 bool waiting_for_stream_; |
| 223 bool stream_done_; | 244 bool stream_done_; |
| 224 scoped_ptr<HttpStream> stream_; | 245 scoped_ptr<HttpStream> stream_; |
| 225 scoped_ptr<WebSocketHandshakeStreamBase> websocket_stream_; | 246 scoped_ptr<WebSocketHandshakeStreamBase> websocket_stream_; |
| 247 scoped_ptr<BidirectionalStreamJob> bidirectional_stream_job_; |
| 226 SSLConfig used_ssl_config_; | 248 SSLConfig used_ssl_config_; |
| 227 ProxyInfo used_proxy_info_; | 249 ProxyInfo used_proxy_info_; |
| 250 int error_status_; |
| 228 | 251 |
| 229 DISALLOW_COPY_AND_ASSIGN(StreamRequestWaiter); | 252 DISALLOW_COPY_AND_ASSIGN(StreamRequestWaiter); |
| 230 }; | 253 }; |
| 231 | 254 |
| 232 class WebSocketSpdyHandshakeStream : public MockWebSocketHandshakeStream { | 255 class WebSocketSpdyHandshakeStream : public MockWebSocketHandshakeStream { |
| 233 public: | 256 public: |
| 234 explicit WebSocketSpdyHandshakeStream( | 257 explicit WebSocketSpdyHandshakeStream( |
| 235 const base::WeakPtr<SpdySession>& spdy_session) | 258 const base::WeakPtr<SpdySession>& spdy_session) |
| 236 : MockWebSocketHandshakeStream(kStreamTypeSpdy), | 259 : MockWebSocketHandshakeStream(kStreamTypeSpdy), |
| 237 spdy_session_(spdy_session) {} | 260 spdy_session_(spdy_session) {} |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 { 2, false }, | 312 { 2, false }, |
| 290 { 1, true}, | 313 { 1, true}, |
| 291 { 2, true}, | 314 { 2, true}, |
| 292 }; | 315 }; |
| 293 | 316 |
| 294 void PreconnectHelperForURL(int num_streams, | 317 void PreconnectHelperForURL(int num_streams, |
| 295 const GURL& url, | 318 const GURL& url, |
| 296 HttpNetworkSession* session) { | 319 HttpNetworkSession* session) { |
| 297 HttpNetworkSessionPeer peer(session); | 320 HttpNetworkSessionPeer peer(session); |
| 298 MockHttpStreamFactoryImplForPreconnect* mock_factory = | 321 MockHttpStreamFactoryImplForPreconnect* mock_factory = |
| 299 new MockHttpStreamFactoryImplForPreconnect(session, false); | 322 new MockHttpStreamFactoryImplForPreconnect(session); |
| 300 peer.SetHttpStreamFactory(scoped_ptr<HttpStreamFactory>(mock_factory)); | 323 peer.SetHttpStreamFactory(scoped_ptr<HttpStreamFactory>(mock_factory)); |
| 301 SSLConfig ssl_config; | 324 SSLConfig ssl_config; |
| 302 session->ssl_config_service()->GetSSLConfig(&ssl_config); | 325 session->ssl_config_service()->GetSSLConfig(&ssl_config); |
| 303 | 326 |
| 304 HttpRequestInfo request; | 327 HttpRequestInfo request; |
| 305 request.method = "GET"; | 328 request.method = "GET"; |
| 306 request.url = url; | 329 request.url = url; |
| 307 request.load_flags = 0; | 330 request.load_flags = 0; |
| 308 | 331 |
| 309 session->http_stream_factory()->PreconnectStreams(num_streams, request, | 332 session->http_stream_factory()->PreconnectStreams(num_streams, request, |
| (...skipping 1030 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1340 EXPECT_EQ(1, GetSocketPoolGroupCount( | 1363 EXPECT_EQ(1, GetSocketPoolGroupCount( |
| 1341 session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL))); | 1364 session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL))); |
| 1342 EXPECT_EQ(0, GetSocketPoolGroupCount( | 1365 EXPECT_EQ(0, GetSocketPoolGroupCount( |
| 1343 session->GetTransportSocketPool( | 1366 session->GetTransportSocketPool( |
| 1344 HttpNetworkSession::WEBSOCKET_SOCKET_POOL))); | 1367 HttpNetworkSession::WEBSOCKET_SOCKET_POOL))); |
| 1345 EXPECT_EQ(0, GetSocketPoolGroupCount( | 1368 EXPECT_EQ(0, GetSocketPoolGroupCount( |
| 1346 session->GetSSLSocketPool(HttpNetworkSession::WEBSOCKET_SOCKET_POOL))); | 1369 session->GetSSLSocketPool(HttpNetworkSession::WEBSOCKET_SOCKET_POOL))); |
| 1347 EXPECT_TRUE(waiter.used_proxy_info().is_direct()); | 1370 EXPECT_TRUE(waiter.used_proxy_info().is_direct()); |
| 1348 } | 1371 } |
| 1349 | 1372 |
| 1373 TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamJob) { |
| 1374 SpdySessionDependencies session_deps(GetParam(), |
| 1375 ProxyService::CreateDirect()); |
| 1376 |
| 1377 MockRead mock_read(ASYNC, OK); |
| 1378 SequencedSocketData socket_data(&mock_read, 1, nullptr, 0); |
| 1379 socket_data.set_connect_data(MockConnect(ASYNC, OK)); |
| 1380 session_deps.socket_factory->AddSocketDataProvider(&socket_data); |
| 1381 |
| 1382 SSLSocketDataProvider ssl_socket_data(ASYNC, OK); |
| 1383 ssl_socket_data.SetNextProto(GetParam()); |
| 1384 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data); |
| 1385 |
| 1386 HostPortPair host_port_pair("www.google.com", 443); |
| 1387 scoped_ptr<HttpNetworkSession> session( |
| 1388 SpdySessionDependencies::SpdyCreateSession(&session_deps)); |
| 1389 |
| 1390 // Now request a stream. |
| 1391 HttpRequestInfo request_info; |
| 1392 request_info.method = "GET"; |
| 1393 request_info.url = GURL("https://www.google.com"); |
| 1394 request_info.load_flags = 0; |
| 1395 |
| 1396 SSLConfig ssl_config; |
| 1397 StreamRequestWaiter waiter; |
| 1398 scoped_ptr<HttpStreamRequest> request( |
| 1399 session->http_stream_factory()->RequestBidirectionalStreamJob( |
| 1400 request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter, |
| 1401 BoundNetLog())); |
| 1402 waiter.WaitForStream(); |
| 1403 EXPECT_TRUE(waiter.stream_done()); |
| 1404 EXPECT_FALSE(waiter.websocket_stream()); |
| 1405 ASSERT_FALSE(waiter.stream()); |
| 1406 ASSERT_TRUE(waiter.bidirectional_stream_job()); |
| 1407 EXPECT_EQ(1, GetSocketPoolGroupCount(session->GetTransportSocketPool( |
| 1408 HttpNetworkSession::NORMAL_SOCKET_POOL))); |
| 1409 EXPECT_EQ(1, GetSocketPoolGroupCount(session->GetSSLSocketPool( |
| 1410 HttpNetworkSession::NORMAL_SOCKET_POOL))); |
| 1411 EXPECT_EQ(0, GetSocketPoolGroupCount(session->GetTransportSocketPool( |
| 1412 HttpNetworkSession::WEBSOCKET_SOCKET_POOL))); |
| 1413 EXPECT_EQ(0, GetSocketPoolGroupCount(session->GetSSLSocketPool( |
| 1414 HttpNetworkSession::WEBSOCKET_SOCKET_POOL))); |
| 1415 EXPECT_TRUE(waiter.used_proxy_info().is_direct()); |
| 1416 ASSERT_EQ(0u, |
| 1417 static_cast<HttpStreamFactoryImpl*>(session->http_stream_factory()) |
| 1418 ->num_orphaned_jobs()); |
| 1419 } |
| 1420 |
| 1421 TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamJobFailure) { |
| 1422 SpdySessionDependencies session_deps(GetParam(), |
| 1423 ProxyService::CreateDirect()); |
| 1424 |
| 1425 MockRead mock_read(ASYNC, OK); |
| 1426 SequencedSocketData socket_data(&mock_read, 1, nullptr, 0); |
| 1427 socket_data.set_connect_data(MockConnect(ASYNC, OK)); |
| 1428 session_deps.socket_factory->AddSocketDataProvider(&socket_data); |
| 1429 |
| 1430 SSLSocketDataProvider ssl_socket_data(ASYNC, OK); |
| 1431 |
| 1432 // If HTTP/1 is used, BidirectionalStreamJob should not be obtained. |
| 1433 ssl_socket_data.SetNextProto(kProtoHTTP11); |
| 1434 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data); |
| 1435 |
| 1436 HostPortPair host_port_pair("www.google.com", 443); |
| 1437 scoped_ptr<HttpNetworkSession> session( |
| 1438 SpdySessionDependencies::SpdyCreateSession(&session_deps)); |
| 1439 |
| 1440 // Now request a stream. |
| 1441 HttpRequestInfo request_info; |
| 1442 request_info.method = "GET"; |
| 1443 request_info.url = GURL("https://www.google.com"); |
| 1444 request_info.load_flags = 0; |
| 1445 |
| 1446 SSLConfig ssl_config; |
| 1447 StreamRequestWaiter waiter; |
| 1448 scoped_ptr<HttpStreamRequest> request( |
| 1449 session->http_stream_factory()->RequestBidirectionalStreamJob( |
| 1450 request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter, |
| 1451 BoundNetLog())); |
| 1452 waiter.WaitForStream(); |
| 1453 EXPECT_TRUE(waiter.stream_done()); |
| 1454 ASSERT_EQ(ERR_FAILED, waiter.error_status()); |
| 1455 EXPECT_FALSE(waiter.websocket_stream()); |
| 1456 ASSERT_FALSE(waiter.stream()); |
| 1457 ASSERT_FALSE(waiter.bidirectional_stream_job()); |
| 1458 EXPECT_EQ(1, GetSocketPoolGroupCount(session->GetTransportSocketPool( |
| 1459 HttpNetworkSession::NORMAL_SOCKET_POOL))); |
| 1460 EXPECT_EQ(1, GetSocketPoolGroupCount(session->GetSSLSocketPool( |
| 1461 HttpNetworkSession::NORMAL_SOCKET_POOL))); |
| 1462 EXPECT_EQ(0, GetSocketPoolGroupCount(session->GetTransportSocketPool( |
| 1463 HttpNetworkSession::WEBSOCKET_SOCKET_POOL))); |
| 1464 EXPECT_EQ(0, GetSocketPoolGroupCount(session->GetSSLSocketPool( |
| 1465 HttpNetworkSession::WEBSOCKET_SOCKET_POOL))); |
| 1466 ASSERT_EQ(0u, |
| 1467 static_cast<HttpStreamFactoryImpl*>(session->http_stream_factory()) |
| 1468 ->num_orphaned_jobs()); |
| 1469 } |
| 1470 |
| 1350 // TODO(ricea): This test can be removed once the new WebSocket stack supports | 1471 // TODO(ricea): This test can be removed once the new WebSocket stack supports |
| 1351 // SPDY. Currently, even if we connect to a SPDY-supporting server, we need to | 1472 // SPDY. Currently, even if we connect to a SPDY-supporting server, we need to |
| 1352 // use plain SSL. | 1473 // use plain SSL. |
| 1353 TEST_P(HttpStreamFactoryTest, RequestWebSocketSpdyHandshakeStreamButGetSSL) { | 1474 TEST_P(HttpStreamFactoryTest, RequestWebSocketSpdyHandshakeStreamButGetSSL) { |
| 1354 SpdySessionDependencies session_deps(GetParam(), | 1475 SpdySessionDependencies session_deps(GetParam(), |
| 1355 ProxyService::CreateDirect()); | 1476 ProxyService::CreateDirect()); |
| 1356 | 1477 |
| 1357 MockRead mock_read(SYNCHRONOUS, ERR_IO_PENDING); | 1478 MockRead mock_read(SYNCHRONOUS, ERR_IO_PENDING); |
| 1358 StaticSocketDataProvider socket_data(&mock_read, 1, nullptr, 0); | 1479 StaticSocketDataProvider socket_data(&mock_read, 1, nullptr, 0); |
| 1359 socket_data.set_connect_data(MockConnect(ASYNC, OK)); | 1480 socket_data.set_connect_data(MockConnect(ASYNC, OK)); |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1544 EXPECT_TRUE(waiter.used_proxy_info().is_direct()); | 1665 EXPECT_TRUE(waiter.used_proxy_info().is_direct()); |
| 1545 | 1666 |
| 1546 // Make sure there is no orphaned job. it is already canceled. | 1667 // Make sure there is no orphaned job. it is already canceled. |
| 1547 ASSERT_EQ(0u, static_cast<HttpStreamFactoryImpl*>( | 1668 ASSERT_EQ(0u, static_cast<HttpStreamFactoryImpl*>( |
| 1548 session->http_stream_factory_for_websocket())->num_orphaned_jobs()); | 1669 session->http_stream_factory_for_websocket())->num_orphaned_jobs()); |
| 1549 } | 1670 } |
| 1550 | 1671 |
| 1551 } // namespace | 1672 } // namespace |
| 1552 | 1673 |
| 1553 } // namespace net | 1674 } // namespace net |
| OLD | NEW |