• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/socket/websocket_transport_client_socket_pool.h"
6 
7 #include <algorithm>
8 
9 #include "base/check_op.h"
10 #include "base/compiler_specific.h"
11 #include "base/functional/bind.h"
12 #include "base/functional/callback_helpers.h"
13 #include "base/location.h"
14 #include "base/notreached.h"
15 #include "base/numerics/safe_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/task/single_thread_task_runner.h"
18 #include "base/values.h"
19 #include "net/base/net_errors.h"
20 #include "net/log/net_log_event_type.h"
21 #include "net/log/net_log_source.h"
22 #include "net/log/net_log_source_type.h"
23 #include "net/socket/client_socket_handle.h"
24 #include "net/socket/connect_job.h"
25 #include "net/socket/connect_job_factory.h"
26 #include "net/socket/stream_socket_handle.h"
27 #include "net/socket/websocket_endpoint_lock_manager.h"
28 #include "net/traffic_annotation/network_traffic_annotation.h"
29 
30 namespace net {
31 
WebSocketTransportClientSocketPool(int max_sockets,int max_sockets_per_group,const ProxyChain & proxy_chain,const CommonConnectJobParams * common_connect_job_params)32 WebSocketTransportClientSocketPool::WebSocketTransportClientSocketPool(
33     int max_sockets,
34     int max_sockets_per_group,
35     const ProxyChain& proxy_chain,
36     const CommonConnectJobParams* common_connect_job_params)
37     : ClientSocketPool(/*is_for_websockets=*/true,
38                        common_connect_job_params,
39                        std::make_unique<ConnectJobFactory>()),
40       proxy_chain_(proxy_chain),
41       max_sockets_(max_sockets) {
42   DCHECK(common_connect_job_params->websocket_endpoint_lock_manager);
43 }
44 
~WebSocketTransportClientSocketPool()45 WebSocketTransportClientSocketPool::~WebSocketTransportClientSocketPool() {
46   // Clean up any pending connect jobs.
47   FlushWithError(ERR_ABORTED, "");
48   CHECK(pending_connects_.empty());
49   CHECK_EQ(0, handed_out_socket_count_);
50   CHECK(stalled_request_queue_.empty());
51   CHECK(stalled_request_map_.empty());
52 }
53 
54 // static
UnlockEndpoint(StreamSocketHandle * handle,WebSocketEndpointLockManager * websocket_endpoint_lock_manager)55 void WebSocketTransportClientSocketPool::UnlockEndpoint(
56     StreamSocketHandle* handle,
57     WebSocketEndpointLockManager* websocket_endpoint_lock_manager) {
58   DCHECK(handle->is_initialized());
59   DCHECK(handle->socket());
60   IPEndPoint address;
61   if (handle->socket()->GetPeerAddress(&address) == OK)
62     websocket_endpoint_lock_manager->UnlockEndpoint(address);
63 }
64 
RequestSocket(const GroupId & group_id,scoped_refptr<SocketParams> params,const std::optional<NetworkTrafficAnnotationTag> & proxy_annotation_tag,RequestPriority priority,const SocketTag & socket_tag,RespectLimits respect_limits,ClientSocketHandle * handle,CompletionOnceCallback callback,const ProxyAuthCallback & proxy_auth_callback,const NetLogWithSource & request_net_log)65 int WebSocketTransportClientSocketPool::RequestSocket(
66     const GroupId& group_id,
67     scoped_refptr<SocketParams> params,
68     const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
69     RequestPriority priority,
70     const SocketTag& socket_tag,
71     RespectLimits respect_limits,
72     ClientSocketHandle* handle,
73     CompletionOnceCallback callback,
74     const ProxyAuthCallback& proxy_auth_callback,
75     const NetLogWithSource& request_net_log) {
76   DCHECK(params);
77   CHECK(!callback.is_null());
78   CHECK(handle);
79   DCHECK(socket_tag == SocketTag());
80 
81   NetLogTcpClientSocketPoolRequestedSocket(request_net_log, group_id);
82   request_net_log.BeginEvent(NetLogEventType::SOCKET_POOL);
83 
84   if (ReachedMaxSocketsLimit() &&
85       respect_limits == ClientSocketPool::RespectLimits::ENABLED) {
86     request_net_log.AddEvent(NetLogEventType::SOCKET_POOL_STALLED_MAX_SOCKETS);
87     stalled_request_queue_.emplace_back(group_id, params, proxy_annotation_tag,
88                                         priority, handle, std::move(callback),
89                                         proxy_auth_callback, request_net_log);
90     auto iterator = stalled_request_queue_.end();
91     --iterator;
92     DCHECK_EQ(handle, iterator->handle);
93     // Because StalledRequestQueue is a std::list, its iterators are guaranteed
94     // to remain valid as long as the elements are not removed. As long as
95     // stalled_request_queue_ and stalled_request_map_ are updated in sync, it
96     // is safe to dereference an iterator in stalled_request_map_ to find the
97     // corresponding list element.
98     stalled_request_map_.insert(
99         StalledRequestMap::value_type(handle, iterator));
100     return ERR_IO_PENDING;
101   }
102 
103   std::unique_ptr<ConnectJobDelegate> connect_job_delegate =
104       std::make_unique<ConnectJobDelegate>(this, std::move(callback), handle,
105                                            request_net_log);
106 
107   std::unique_ptr<ConnectJob> connect_job =
108       CreateConnectJob(group_id, params, proxy_chain_, proxy_annotation_tag,
109                        priority, SocketTag(), connect_job_delegate.get());
110 
111   int result = connect_job_delegate->Connect(std::move(connect_job));
112 
113   // Regardless of the outcome of |connect_job|, it will always be bound to
114   // |handle|, since this pool uses early-binding. So the binding is logged
115   // here, without waiting for the result.
116   request_net_log.AddEventReferencingSource(
117       NetLogEventType::SOCKET_POOL_BOUND_TO_CONNECT_JOB,
118       connect_job_delegate->connect_job_net_log().source());
119 
120   if (result == ERR_IO_PENDING) {
121     // TODO(ricea): Implement backup job timer?
122     AddJob(handle, std::move(connect_job_delegate));
123   } else {
124     TryHandOutSocket(result, connect_job_delegate.get());
125   }
126 
127   return result;
128 }
129 
RequestSockets(const GroupId & group_id,scoped_refptr<SocketParams> params,const std::optional<NetworkTrafficAnnotationTag> & proxy_annotation_tag,int num_sockets,CompletionOnceCallback callback,const NetLogWithSource & net_log)130 int WebSocketTransportClientSocketPool::RequestSockets(
131     const GroupId& group_id,
132     scoped_refptr<SocketParams> params,
133     const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
134     int num_sockets,
135     CompletionOnceCallback callback,
136     const NetLogWithSource& net_log) {
137   NOTIMPLEMENTED();
138   return OK;
139 }
140 
SetPriority(const GroupId & group_id,ClientSocketHandle * handle,RequestPriority priority)141 void WebSocketTransportClientSocketPool::SetPriority(const GroupId& group_id,
142                                                      ClientSocketHandle* handle,
143                                                      RequestPriority priority) {
144   // Since sockets requested by RequestSocket are bound early and
145   // stalled_request_{queue,map} don't take priorities into account, there's
146   // nothing to do within the pool to change priority of the request.
147   // TODO(rdsmith, ricea): Make stalled_request_{queue,map} take priorities
148   // into account.
149   // TODO(rdsmith, chlily): Investigate plumbing the reprioritization request to
150   // the connect job.
151 }
152 
CancelRequest(const GroupId & group_id,ClientSocketHandle * handle,bool cancel_connect_job)153 void WebSocketTransportClientSocketPool::CancelRequest(
154     const GroupId& group_id,
155     ClientSocketHandle* handle,
156     bool cancel_connect_job) {
157   DCHECK(!handle->is_initialized());
158   if (DeleteStalledRequest(handle))
159     return;
160   std::unique_ptr<StreamSocket> socket = handle->PassSocket();
161   if (socket)
162     ReleaseSocket(handle->group_id(), std::move(socket),
163                   handle->group_generation());
164   if (DeleteJob(handle)) {
165     CHECK(!base::Contains(pending_callbacks_,
166                           reinterpret_cast<ClientSocketHandleID>(handle)));
167   } else {
168     pending_callbacks_.erase(reinterpret_cast<ClientSocketHandleID>(handle));
169   }
170 
171   ActivateStalledRequest();
172 }
173 
ReleaseSocket(const GroupId & group_id,std::unique_ptr<StreamSocket> socket,int64_t generation)174 void WebSocketTransportClientSocketPool::ReleaseSocket(
175     const GroupId& group_id,
176     std::unique_ptr<StreamSocket> socket,
177     int64_t generation) {
178   CHECK_GT(handed_out_socket_count_, 0);
179   --handed_out_socket_count_;
180 
181   ActivateStalledRequest();
182 }
183 
FlushWithError(int error,const char * net_log_reason_utf8)184 void WebSocketTransportClientSocketPool::FlushWithError(
185     int error,
186     const char* net_log_reason_utf8) {
187   DCHECK_NE(error, OK);
188 
189   // Sockets which are in LOAD_STATE_CONNECTING are in danger of unlocking
190   // sockets waiting for the endpoint lock. If they connected synchronously,
191   // then OnConnectJobComplete(). The |flushing_| flag tells this object to
192   // ignore spurious calls to OnConnectJobComplete(). It is safe to ignore those
193   // calls because this method will delete the jobs and call their callbacks
194   // anyway.
195   flushing_ = true;
196   for (auto it = pending_connects_.begin(); it != pending_connects_.end();) {
197     InvokeUserCallbackLater(it->second->socket_handle(),
198                             it->second->release_callback(), error);
199     it->second->connect_job_net_log().AddEventWithStringParams(
200         NetLogEventType::SOCKET_POOL_CLOSING_SOCKET, "reason",
201         net_log_reason_utf8);
202     it = pending_connects_.erase(it);
203   }
204   for (auto& stalled_request : stalled_request_queue_) {
205     InvokeUserCallbackLater(stalled_request.handle,
206                             std::move(stalled_request.callback), error);
207   }
208   stalled_request_map_.clear();
209   stalled_request_queue_.clear();
210   flushing_ = false;
211 }
212 
CloseIdleSockets(const char * net_log_reason_utf8)213 void WebSocketTransportClientSocketPool::CloseIdleSockets(
214     const char* net_log_reason_utf8) {
215   // We have no idle sockets.
216 }
217 
CloseIdleSocketsInGroup(const GroupId & group_id,const char * net_log_reason_utf8)218 void WebSocketTransportClientSocketPool::CloseIdleSocketsInGroup(
219     const GroupId& group_id,
220     const char* net_log_reason_utf8) {
221   // We have no idle sockets.
222 }
223 
IdleSocketCount() const224 int WebSocketTransportClientSocketPool::IdleSocketCount() const {
225   return 0;
226 }
227 
IdleSocketCountInGroup(const GroupId & group_id) const228 size_t WebSocketTransportClientSocketPool::IdleSocketCountInGroup(
229     const GroupId& group_id) const {
230   return 0;
231 }
232 
GetLoadState(const GroupId & group_id,const ClientSocketHandle * handle) const233 LoadState WebSocketTransportClientSocketPool::GetLoadState(
234     const GroupId& group_id,
235     const ClientSocketHandle* handle) const {
236   if (stalled_request_map_.find(handle) != stalled_request_map_.end())
237     return LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET;
238   if (pending_callbacks_.count(reinterpret_cast<ClientSocketHandleID>(handle)))
239     return LOAD_STATE_CONNECTING;
240   return LookupConnectJob(handle)->GetLoadState();
241 }
242 
GetInfoAsValue(const std::string & name,const std::string & type) const243 base::Value WebSocketTransportClientSocketPool::GetInfoAsValue(
244     const std::string& name,
245     const std::string& type) const {
246   auto dict = base::Value::Dict()
247                   .Set("name", name)
248                   .Set("type", type)
249                   .Set("handed_out_socket_count", handed_out_socket_count_)
250                   .Set("connecting_socket_count",
251                        static_cast<int>(pending_connects_.size()))
252                   .Set("idle_socket_count", 0)
253                   .Set("max_socket_count", max_sockets_)
254                   .Set("max_sockets_per_group", max_sockets_);
255   return base::Value(std::move(dict));
256 }
257 
HasActiveSocket(const GroupId & group_id) const258 bool WebSocketTransportClientSocketPool::HasActiveSocket(
259     const GroupId& group_id) const {
260   // This method is not supported for WebSocket.
261   NOTREACHED();
262 }
263 
IsStalled() const264 bool WebSocketTransportClientSocketPool::IsStalled() const {
265   return !stalled_request_queue_.empty();
266 }
267 
AddHigherLayeredPool(HigherLayeredPool * higher_pool)268 void WebSocketTransportClientSocketPool::AddHigherLayeredPool(
269     HigherLayeredPool* higher_pool) {
270   // This class doesn't use connection limits like the pools for HTTP do, so no
271   // need to track higher layered pools.
272 }
273 
RemoveHigherLayeredPool(HigherLayeredPool * higher_pool)274 void WebSocketTransportClientSocketPool::RemoveHigherLayeredPool(
275     HigherLayeredPool* higher_pool) {
276   // This class doesn't use connection limits like the pools for HTTP do, so no
277   // need to track higher layered pools.
278 }
279 
TryHandOutSocket(int result,ConnectJobDelegate * connect_job_delegate)280 bool WebSocketTransportClientSocketPool::TryHandOutSocket(
281     int result,
282     ConnectJobDelegate* connect_job_delegate) {
283   DCHECK_NE(result, ERR_IO_PENDING);
284 
285   std::unique_ptr<StreamSocket> socket =
286       connect_job_delegate->connect_job()->PassSocket();
287   LoadTimingInfo::ConnectTiming connect_timing =
288       connect_job_delegate->connect_job()->connect_timing();
289   ClientSocketHandle* const handle = connect_job_delegate->socket_handle();
290   NetLogWithSource request_net_log = connect_job_delegate->request_net_log();
291 
292   if (result == OK) {
293     DCHECK(socket);
294 
295     HandOutSocket(std::move(socket), connect_timing, handle, request_net_log);
296 
297     request_net_log.EndEvent(NetLogEventType::SOCKET_POOL);
298 
299     return true;
300   }
301 
302   bool handed_out_socket = false;
303 
304   // If we got a socket, it must contain error information so pass that
305   // up so that the caller can retrieve it.
306   handle->SetAdditionalErrorState(connect_job_delegate->connect_job());
307   if (socket) {
308     HandOutSocket(std::move(socket), connect_timing, handle, request_net_log);
309     handed_out_socket = true;
310   }
311 
312   request_net_log.EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL,
313                                            result);
314 
315   return handed_out_socket;
316 }
317 
OnConnectJobComplete(int result,ConnectJobDelegate * connect_job_delegate)318 void WebSocketTransportClientSocketPool::OnConnectJobComplete(
319     int result,
320     ConnectJobDelegate* connect_job_delegate) {
321   DCHECK_NE(ERR_IO_PENDING, result);
322 
323   // See comment in FlushWithError.
324   if (flushing_) {
325     // Just delete the socket.
326     std::unique_ptr<StreamSocket> socket =
327         connect_job_delegate->connect_job()->PassSocket();
328     return;
329   }
330 
331   bool handed_out_socket = TryHandOutSocket(result, connect_job_delegate);
332 
333   CompletionOnceCallback callback = connect_job_delegate->release_callback();
334 
335   ClientSocketHandle* const handle = connect_job_delegate->socket_handle();
336 
337   bool delete_succeeded = DeleteJob(handle);
338   CHECK(delete_succeeded);
339 
340   connect_job_delegate = nullptr;
341 
342   if (!handed_out_socket)
343     ActivateStalledRequest();
344 
345   InvokeUserCallbackLater(handle, std::move(callback), result);
346 }
347 
InvokeUserCallbackLater(ClientSocketHandle * handle,CompletionOnceCallback callback,int rv)348 void WebSocketTransportClientSocketPool::InvokeUserCallbackLater(
349     ClientSocketHandle* handle,
350     CompletionOnceCallback callback,
351     int rv) {
352   const auto handle_id = reinterpret_cast<ClientSocketHandleID>(handle);
353   CHECK(!pending_callbacks_.count(handle_id));
354   pending_callbacks_.insert(handle_id);
355   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
356       FROM_HERE,
357       base::BindOnce(&WebSocketTransportClientSocketPool::InvokeUserCallback,
358                      weak_factory_.GetWeakPtr(), handle_id,
359                      handle->GetWeakPtr(), std::move(callback), rv));
360 }
361 
InvokeUserCallback(ClientSocketHandleID handle_id,base::WeakPtr<ClientSocketHandle> weak_handle,CompletionOnceCallback callback,int rv)362 void WebSocketTransportClientSocketPool::InvokeUserCallback(
363     ClientSocketHandleID handle_id,
364     base::WeakPtr<ClientSocketHandle> weak_handle,
365     CompletionOnceCallback callback,
366     int rv) {
367   if (pending_callbacks_.erase(handle_id)) {
368     CHECK(weak_handle);
369     std::move(callback).Run(rv);
370   }
371 }
372 
ReachedMaxSocketsLimit() const373 bool WebSocketTransportClientSocketPool::ReachedMaxSocketsLimit() const {
374   return handed_out_socket_count_ >= max_sockets_ ||
375          base::checked_cast<int>(pending_connects_.size()) >=
376              max_sockets_ - handed_out_socket_count_;
377 }
378 
HandOutSocket(std::unique_ptr<StreamSocket> socket,const LoadTimingInfo::ConnectTiming & connect_timing,ClientSocketHandle * handle,const NetLogWithSource & net_log)379 void WebSocketTransportClientSocketPool::HandOutSocket(
380     std::unique_ptr<StreamSocket> socket,
381     const LoadTimingInfo::ConnectTiming& connect_timing,
382     ClientSocketHandle* handle,
383     const NetLogWithSource& net_log) {
384   DCHECK(socket);
385   DCHECK_EQ(StreamSocketHandle::SocketReuseType::kUnused, handle->reuse_type());
386   DCHECK_EQ(0, handle->idle_time().InMicroseconds());
387 
388   handle->SetSocket(std::move(socket));
389   handle->set_group_generation(0);
390   handle->set_connect_timing(connect_timing);
391 
392   net_log.AddEventReferencingSource(
393       NetLogEventType::SOCKET_POOL_BOUND_TO_SOCKET,
394       handle->socket()->NetLog().source());
395 
396   ++handed_out_socket_count_;
397 }
398 
AddJob(ClientSocketHandle * handle,std::unique_ptr<ConnectJobDelegate> delegate)399 void WebSocketTransportClientSocketPool::AddJob(
400     ClientSocketHandle* handle,
401     std::unique_ptr<ConnectJobDelegate> delegate) {
402   bool inserted =
403       pending_connects_
404           .insert(PendingConnectsMap::value_type(handle, std::move(delegate)))
405           .second;
406   CHECK(inserted);
407 }
408 
DeleteJob(ClientSocketHandle * handle)409 bool WebSocketTransportClientSocketPool::DeleteJob(ClientSocketHandle* handle) {
410   auto it = pending_connects_.find(handle);
411   if (it == pending_connects_.end())
412     return false;
413   // Deleting a ConnectJob which holds an endpoint lock can lead to a different
414   // ConnectJob proceeding to connect. If the connect proceeds synchronously
415   // (usually because of a failure) then it can trigger that job to be
416   // deleted.
417   pending_connects_.erase(it);
418   return true;
419 }
420 
LookupConnectJob(const ClientSocketHandle * handle) const421 const ConnectJob* WebSocketTransportClientSocketPool::LookupConnectJob(
422     const ClientSocketHandle* handle) const {
423   auto it = pending_connects_.find(handle);
424   CHECK(it != pending_connects_.end());
425   return it->second->connect_job();
426 }
427 
ActivateStalledRequest()428 void WebSocketTransportClientSocketPool::ActivateStalledRequest() {
429   // Usually we will only be able to activate one stalled request at a time,
430   // however if all the connects fail synchronously for some reason, we may be
431   // able to clear the whole queue at once.
432   while (!stalled_request_queue_.empty() && !ReachedMaxSocketsLimit()) {
433     StalledRequest request = std::move(stalled_request_queue_.front());
434     stalled_request_queue_.pop_front();
435     stalled_request_map_.erase(request.handle);
436 
437     auto split_callback = base::SplitOnceCallback(std::move(request.callback));
438 
439     int rv = RequestSocket(
440         request.group_id, request.params, request.proxy_annotation_tag,
441         request.priority, SocketTag(),
442         // Stalled requests can't have |respect_limits|
443         // DISABLED.
444         RespectLimits::ENABLED, request.handle, std::move(split_callback.first),
445         request.proxy_auth_callback, request.net_log);
446 
447     // ActivateStalledRequest() never returns synchronously, so it is never
448     // called re-entrantly.
449     if (rv != ERR_IO_PENDING)
450       InvokeUserCallbackLater(request.handle, std::move(split_callback.second),
451                               rv);
452   }
453 }
454 
DeleteStalledRequest(ClientSocketHandle * handle)455 bool WebSocketTransportClientSocketPool::DeleteStalledRequest(
456     ClientSocketHandle* handle) {
457   auto it = stalled_request_map_.find(handle);
458   if (it == stalled_request_map_.end())
459     return false;
460   stalled_request_queue_.erase(it->second);
461   stalled_request_map_.erase(it);
462   return true;
463 }
464 
ConnectJobDelegate(WebSocketTransportClientSocketPool * owner,CompletionOnceCallback callback,ClientSocketHandle * socket_handle,const NetLogWithSource & request_net_log)465 WebSocketTransportClientSocketPool::ConnectJobDelegate::ConnectJobDelegate(
466     WebSocketTransportClientSocketPool* owner,
467     CompletionOnceCallback callback,
468     ClientSocketHandle* socket_handle,
469     const NetLogWithSource& request_net_log)
470     : owner_(owner),
471       callback_(std::move(callback)),
472       socket_handle_(socket_handle),
473       request_net_log_(request_net_log) {}
474 
475 WebSocketTransportClientSocketPool::ConnectJobDelegate::~ConnectJobDelegate() =
476     default;
477 
478 void
OnConnectJobComplete(int result,ConnectJob * job)479 WebSocketTransportClientSocketPool::ConnectJobDelegate::OnConnectJobComplete(
480     int result,
481     ConnectJob* job) {
482   DCHECK_EQ(job, connect_job_.get());
483   owner_->OnConnectJobComplete(result, this);
484 }
485 
OnNeedsProxyAuth(const HttpResponseInfo & response,HttpAuthController * auth_controller,base::OnceClosure restart_with_auth_callback,ConnectJob * job)486 void WebSocketTransportClientSocketPool::ConnectJobDelegate::OnNeedsProxyAuth(
487     const HttpResponseInfo& response,
488     HttpAuthController* auth_controller,
489     base::OnceClosure restart_with_auth_callback,
490     ConnectJob* job) {
491   // This class isn't used for proxies.
492   NOTREACHED();
493 }
494 
Connect(std::unique_ptr<ConnectJob> connect_job)495 int WebSocketTransportClientSocketPool::ConnectJobDelegate::Connect(
496     std::unique_ptr<ConnectJob> connect_job) {
497   connect_job_ = std::move(connect_job);
498   return connect_job_->Connect();
499 }
500 
501 const NetLogWithSource&
connect_job_net_log()502 WebSocketTransportClientSocketPool::ConnectJobDelegate::connect_job_net_log() {
503   return connect_job_->net_log();
504 }
505 
StalledRequest(const GroupId & group_id,const scoped_refptr<SocketParams> & params,const std::optional<NetworkTrafficAnnotationTag> & proxy_annotation_tag,RequestPriority priority,ClientSocketHandle * handle,CompletionOnceCallback callback,const ProxyAuthCallback & proxy_auth_callback,const NetLogWithSource & net_log)506 WebSocketTransportClientSocketPool::StalledRequest::StalledRequest(
507     const GroupId& group_id,
508     const scoped_refptr<SocketParams>& params,
509     const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
510     RequestPriority priority,
511     ClientSocketHandle* handle,
512     CompletionOnceCallback callback,
513     const ProxyAuthCallback& proxy_auth_callback,
514     const NetLogWithSource& net_log)
515     : group_id(group_id),
516       params(params),
517       proxy_annotation_tag(proxy_annotation_tag),
518       priority(priority),
519       handle(handle),
520       callback(std::move(callback)),
521       proxy_auth_callback(proxy_auth_callback),
522       net_log(net_log) {}
523 
524 WebSocketTransportClientSocketPool::StalledRequest::StalledRequest(
525     StalledRequest&& other) = default;
526 
527 WebSocketTransportClientSocketPool::StalledRequest::~StalledRequest() = default;
528 
529 }  // namespace net
530