• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include "libcef/browser/server_impl.h"
6 
7 #include "libcef/browser/thread_util.h"
8 #include "libcef/common/request_impl.h"
9 #include "libcef/common/task_runner_impl.h"
10 
11 #include "base/bind.h"
12 #include "base/format_macros.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/task/thread_pool.h"
16 #include "base/threading/thread.h"
17 #include "net/base/net_errors.h"
18 #include "net/http/http_request_headers.h"
19 #include "net/server/http_server_request_info.h"
20 #include "net/server/http_server_response_info.h"
21 #include "net/socket/server_socket.h"
22 #include "net/socket/tcp_server_socket.h"
23 #include "net/traffic_annotation/network_traffic_annotation.h"
24 
25 #define CEF_CURRENTLY_ON_HT() CurrentlyOnHandlerThread()
26 #define CEF_REQUIRE_HT() DCHECK(CEF_CURRENTLY_ON_HT())
27 
28 #define CEF_REQUIRE_HT_RETURN(var)              \
29   if (!CEF_CURRENTLY_ON_HT()) {                 \
30     NOTREACHED() << "called on invalid thread"; \
31     return var;                                 \
32   }
33 
34 #define CEF_REQUIRE_HT_RETURN_VOID()            \
35   if (!CEF_CURRENTLY_ON_HT()) {                 \
36     NOTREACHED() << "called on invalid thread"; \
37     return;                                     \
38   }
39 
40 #define CEF_POST_TASK_HT(task) task_runner_->PostTask(FROM_HERE, task);
41 
42 namespace {
43 
44 const char kReferrerLowerCase[] = "referer";
45 
46 // Wrap a string in a unique_ptr to avoid extra copies.
CreateUniqueString(const void * data,size_t data_size)47 std::unique_ptr<std::string> CreateUniqueString(const void* data,
48                                                 size_t data_size) {
49   std::unique_ptr<std::string> ptr;
50   if (data && data_size > 0) {
51     ptr.reset(new std::string(static_cast<const char*>(data), data_size));
52   } else {
53     ptr.reset(new std::string());
54   }
55   return ptr;
56 }
57 
CreateRequest(const std::string & address,const net::HttpServerRequestInfo & info,bool is_websocket)58 CefRefPtr<CefRequest> CreateRequest(const std::string& address,
59                                     const net::HttpServerRequestInfo& info,
60                                     bool is_websocket) {
61   DCHECK(!address.empty());
62   DCHECK(!info.method.empty());
63   DCHECK(!info.path.empty());
64 
65   CefRefPtr<CefPostData> post_data;
66   if (!info.data.empty()) {
67     post_data = CefPostData::Create();
68     CefRefPtr<CefPostDataElement> post_element = CefPostDataElement::Create();
69     post_element->SetToBytes(info.data.size(), info.data.data());
70     post_data->AddElement(post_element);
71   }
72 
73   std::string referer;
74 
75   CefRequest::HeaderMap header_map;
76   if (!info.headers.empty()) {
77     net::HttpServerRequestInfo::HeadersMap::const_iterator it =
78         info.headers.begin();
79     for (; it != info.headers.end(); ++it) {
80       // Don't include Referer in the header map.
81       if (base::LowerCaseEqualsASCII(it->first, kReferrerLowerCase)) {
82         referer = it->second;
83       } else {
84         header_map.insert(std::make_pair(it->first, it->second));
85       }
86     }
87   }
88 
89   CefRefPtr<CefRequestImpl> request = new CefRequestImpl();
90   request->Set((is_websocket ? "ws://" : "http://") + address + info.path,
91                info.method, post_data, header_map);
92   if (!referer.empty())
93     request->SetReferrer(referer, REFERRER_POLICY_DEFAULT);
94   request->SetReadOnly(true);
95   return request;
96 }
97 
98 // Callback implementation for WebSocket acceptance. Always executes on the UI
99 // thread so we can avoid multiple execution by clearing the |impl_| reference.
100 class AcceptWebSocketCallback : public CefCallback {
101  public:
AcceptWebSocketCallback(CefRefPtr<CefServerImpl> impl,int connection_id,net::HttpServerRequestInfo request_info)102   AcceptWebSocketCallback(CefRefPtr<CefServerImpl> impl,
103                           int connection_id,
104                           net::HttpServerRequestInfo request_info)
105       : impl_(impl),
106         connection_id_(connection_id),
107         request_info_(request_info) {}
108 
109   AcceptWebSocketCallback(const AcceptWebSocketCallback&) = delete;
110   AcceptWebSocketCallback& operator=(const AcceptWebSocketCallback&) = delete;
111 
~AcceptWebSocketCallback()112   ~AcceptWebSocketCallback() override {
113     if (impl_)
114       impl_->ContinueWebSocketRequest(connection_id_, request_info_, false);
115   }
116 
Continue()117   void Continue() override {
118     if (!CEF_CURRENTLY_ON_UIT()) {
119       CEF_POST_TASK(CEF_UIT,
120                     base::BindOnce(&AcceptWebSocketCallback::Continue, this));
121       return;
122     }
123     if (!impl_)
124       return;
125     impl_->ContinueWebSocketRequest(connection_id_, request_info_, true);
126     impl_ = nullptr;
127   }
128 
Cancel()129   void Cancel() override {
130     if (!CEF_CURRENTLY_ON_UIT()) {
131       CEF_POST_TASK(CEF_UIT,
132                     base::BindOnce(&AcceptWebSocketCallback::Cancel, this));
133       return;
134     }
135     if (!impl_)
136       return;
137     impl_->ContinueWebSocketRequest(connection_id_, request_info_, false);
138     impl_ = nullptr;
139   }
140 
141  private:
142   CefRefPtr<CefServerImpl> impl_;
143   int connection_id_;
144   net::HttpServerRequestInfo request_info_;
145 
146   IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(AcceptWebSocketCallback);
147 };
148 
149 }  // namespace
150 
151 // CefServer
152 
153 // static
CreateServer(const CefString & address,uint16 port,int backlog,CefRefPtr<CefServerHandler> handler)154 void CefServer::CreateServer(const CefString& address,
155                              uint16 port,
156                              int backlog,
157                              CefRefPtr<CefServerHandler> handler) {
158   CefRefPtr<CefServerImpl> server(new CefServerImpl(handler));
159   server->Start(address, port, backlog);
160 }
161 
162 // CefServerImpl
163 
164 struct CefServerImpl::ConnectionInfo {
ConnectionInfoCefServerImpl::ConnectionInfo165   ConnectionInfo() : is_websocket(false), is_websocket_pending(false) {}
166 
167   // True if this connection is a WebSocket connection.
168   bool is_websocket;
169   bool is_websocket_pending;
170 };
171 
CefServerImpl(CefRefPtr<CefServerHandler> handler)172 CefServerImpl::CefServerImpl(CefRefPtr<CefServerHandler> handler)
173     : handler_(handler) {
174   DCHECK(handler_);
175 }
176 
Start(const std::string & address,uint16 port,int backlog)177 void CefServerImpl::Start(const std::string& address,
178                           uint16 port,
179                           int backlog) {
180   DCHECK(!address.empty());
181   CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefServerImpl::StartOnUIThread, this,
182                                         address, port, backlog));
183 }
184 
GetTaskRunner()185 CefRefPtr<CefTaskRunner> CefServerImpl::GetTaskRunner() {
186   if (task_runner_)
187     return new CefTaskRunnerImpl(task_runner_);
188   return nullptr;
189 }
190 
Shutdown()191 void CefServerImpl::Shutdown() {
192   CEF_POST_TASK_HT(
193       base::BindOnce(&CefServerImpl::ShutdownOnHandlerThread, this));
194 }
195 
IsRunning()196 bool CefServerImpl::IsRunning() {
197   CEF_REQUIRE_HT_RETURN(false);
198   return !!server_.get();
199 }
200 
GetAddress()201 CefString CefServerImpl::GetAddress() {
202   return address_;
203 }
204 
HasConnection()205 bool CefServerImpl::HasConnection() {
206   CEF_REQUIRE_HT_RETURN(false);
207   return !connection_info_map_.empty();
208 }
209 
IsValidConnection(int connection_id)210 bool CefServerImpl::IsValidConnection(int connection_id) {
211   CEF_REQUIRE_HT_RETURN(false);
212   return connection_info_map_.find(connection_id) != connection_info_map_.end();
213 }
214 
SendHttp200Response(int connection_id,const CefString & content_type,const void * data,size_t data_size)215 void CefServerImpl::SendHttp200Response(int connection_id,
216                                         const CefString& content_type,
217                                         const void* data,
218                                         size_t data_size) {
219   SendHttp200ResponseInternal(connection_id, content_type,
220                               CreateUniqueString(data, data_size));
221 }
222 
SendHttp404Response(int connection_id)223 void CefServerImpl::SendHttp404Response(int connection_id) {
224   if (!CEF_CURRENTLY_ON_HT()) {
225     CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttp404Response, this,
226                                     connection_id));
227     return;
228   }
229 
230   if (!ValidateServer())
231     return;
232 
233   ConnectionInfo* info = GetConnectionInfo(connection_id);
234   if (!info)
235     return;
236 
237   if (info->is_websocket) {
238     LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
239                << connection_id;
240     return;
241   }
242 
243   server_->Send404(connection_id, MISSING_TRAFFIC_ANNOTATION);
244   server_->Close(connection_id);
245 }
246 
SendHttp500Response(int connection_id,const CefString & error_message)247 void CefServerImpl::SendHttp500Response(int connection_id,
248                                         const CefString& error_message) {
249   if (!CEF_CURRENTLY_ON_HT()) {
250     CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttp500Response, this,
251                                     connection_id, error_message));
252     return;
253   }
254 
255   if (!ValidateServer())
256     return;
257 
258   ConnectionInfo* info = GetConnectionInfo(connection_id);
259   if (!info)
260     return;
261 
262   if (info->is_websocket) {
263     LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
264                << connection_id;
265     return;
266   }
267 
268   server_->Send500(connection_id, error_message, MISSING_TRAFFIC_ANNOTATION);
269   server_->Close(connection_id);
270 }
271 
SendHttpResponse(int connection_id,int response_code,const CefString & content_type,int64 content_length,const HeaderMap & extra_headers)272 void CefServerImpl::SendHttpResponse(int connection_id,
273                                      int response_code,
274                                      const CefString& content_type,
275                                      int64 content_length,
276                                      const HeaderMap& extra_headers) {
277   if (!CEF_CURRENTLY_ON_HT()) {
278     CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttpResponse, this,
279                                     connection_id, response_code, content_type,
280                                     content_length, extra_headers));
281     return;
282   }
283 
284   if (!ValidateServer())
285     return;
286 
287   ConnectionInfo* info = GetConnectionInfo(connection_id);
288   if (!info)
289     return;
290 
291   if (info->is_websocket) {
292     LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
293                << connection_id;
294     return;
295   }
296 
297   net::HttpServerResponseInfo response(
298       static_cast<net::HttpStatusCode>(response_code));
299 
300   HeaderMap::const_iterator it = extra_headers.begin();
301   for (; it != extra_headers.end(); ++it)
302     response.AddHeader(it->first, it->second);
303 
304   response.AddHeader(net::HttpRequestHeaders::kContentType, content_type);
305   if (content_length >= 0) {
306     response.AddHeader(
307         net::HttpRequestHeaders::kContentLength,
308         base::StringPrintf("%" PRIuS, static_cast<size_t>(content_length)));
309   }
310 
311   server_->SendResponse(connection_id, response, MISSING_TRAFFIC_ANNOTATION);
312   if (content_length == 0) {
313     server_->Close(connection_id);
314   }
315 }
316 
SendRawData(int connection_id,const void * data,size_t data_size)317 void CefServerImpl::SendRawData(int connection_id,
318                                 const void* data,
319                                 size_t data_size) {
320   if (!data || data_size == 0)
321     return;
322   SendRawDataInternal(connection_id, CreateUniqueString(data, data_size));
323 }
324 
CloseConnection(int connection_id)325 void CefServerImpl::CloseConnection(int connection_id) {
326   if (!CEF_CURRENTLY_ON_HT()) {
327     CEF_POST_TASK_HT(
328         base::BindOnce(&CefServerImpl::CloseConnection, this, connection_id));
329     return;
330   }
331 
332   if (ValidateServer() && GetConnectionInfo(connection_id)) {
333     server_->Close(connection_id);
334   }
335 }
336 
SendWebSocketMessage(int connection_id,const void * data,size_t data_size)337 void CefServerImpl::SendWebSocketMessage(int connection_id,
338                                          const void* data,
339                                          size_t data_size) {
340   if (!data || data_size == 0)
341     return;
342   SendWebSocketMessageInternal(connection_id,
343                                CreateUniqueString(data, data_size));
344 }
345 
ContinueWebSocketRequest(int connection_id,const net::HttpServerRequestInfo & request_info,bool allow)346 void CefServerImpl::ContinueWebSocketRequest(
347     int connection_id,
348     const net::HttpServerRequestInfo& request_info,
349     bool allow) {
350   if (!CEF_CURRENTLY_ON_HT()) {
351     CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::ContinueWebSocketRequest,
352                                     this, connection_id, request_info, allow));
353     return;
354   }
355 
356   if (!ValidateServer())
357     return;
358 
359   ConnectionInfo* info = GetConnectionInfo(connection_id);
360   DCHECK(info);
361   if (!info)
362     return;
363 
364   DCHECK(info->is_websocket);
365   DCHECK(info->is_websocket_pending);
366   if (!info->is_websocket || !info->is_websocket_pending)
367     return;
368 
369   info->is_websocket_pending = false;
370 
371   if (allow) {
372     server_->AcceptWebSocket(connection_id, request_info,
373                              MISSING_TRAFFIC_ANNOTATION);
374     handler_->OnWebSocketConnected(this, connection_id);
375   } else {
376     server_->Close(connection_id);
377   }
378 }
379 
SendHttp200ResponseInternal(int connection_id,const CefString & content_type,std::unique_ptr<std::string> data)380 void CefServerImpl::SendHttp200ResponseInternal(
381     int connection_id,
382     const CefString& content_type,
383     std::unique_ptr<std::string> data) {
384   if (!CEF_CURRENTLY_ON_HT()) {
385     CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttp200ResponseInternal,
386                                     this, connection_id, content_type,
387                                     std::move(data)));
388     return;
389   }
390 
391   if (!ValidateServer())
392     return;
393 
394   ConnectionInfo* info = GetConnectionInfo(connection_id);
395   if (!info)
396     return;
397 
398   if (info->is_websocket) {
399     LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
400                << connection_id;
401     return;
402   }
403 
404   server_->Send200(connection_id, *data, content_type,
405                    MISSING_TRAFFIC_ANNOTATION);
406   server_->Close(connection_id);
407 }
408 
SendRawDataInternal(int connection_id,std::unique_ptr<std::string> data)409 void CefServerImpl::SendRawDataInternal(int connection_id,
410                                         std::unique_ptr<std::string> data) {
411   if (!CEF_CURRENTLY_ON_HT()) {
412     CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendRawDataInternal, this,
413                                     connection_id, std::move(data)));
414     return;
415   }
416 
417   if (!ValidateServer())
418     return;
419 
420   if (!GetConnectionInfo(connection_id))
421     return;
422 
423   server_->SendRaw(connection_id, *data, MISSING_TRAFFIC_ANNOTATION);
424 }
425 
SendWebSocketMessageInternal(int connection_id,std::unique_ptr<std::string> data)426 void CefServerImpl::SendWebSocketMessageInternal(
427     int connection_id,
428     std::unique_ptr<std::string> data) {
429   if (!CEF_CURRENTLY_ON_HT()) {
430     CEF_POST_TASK_HT(
431         base::BindOnce(&CefServerImpl::SendWebSocketMessageInternal, this,
432                        connection_id, std::move(data)));
433     return;
434   }
435 
436   if (!ValidateServer())
437     return;
438 
439   ConnectionInfo* info = GetConnectionInfo(connection_id);
440   if (!info)
441     return;
442 
443   if (!info->is_websocket || info->is_websocket_pending) {
444     LOG(ERROR) << "Invalid attempt to send WebSocket message for connection_id "
445                << connection_id;
446     return;
447   }
448 
449   server_->SendOverWebSocket(connection_id, *data, MISSING_TRAFFIC_ANNOTATION);
450 }
451 
OnConnect(int connection_id)452 void CefServerImpl::OnConnect(int connection_id) {
453   CEF_REQUIRE_HT();
454 
455   CreateConnectionInfo(connection_id);
456   handler_->OnClientConnected(this, connection_id);
457 }
458 
OnHttpRequest(int connection_id,const net::HttpServerRequestInfo & request_info)459 void CefServerImpl::OnHttpRequest(
460     int connection_id,
461     const net::HttpServerRequestInfo& request_info) {
462   CEF_REQUIRE_HT();
463 
464   ConnectionInfo* info = GetConnectionInfo(connection_id);
465   DCHECK(info);
466   if (!info)
467     return;
468 
469   DCHECK(!info->is_websocket);
470 
471   handler_->OnHttpRequest(this, connection_id, request_info.peer.ToString(),
472                           CreateRequest(address_, request_info, false));
473 }
474 
OnWebSocketRequest(int connection_id,const net::HttpServerRequestInfo & request_info)475 void CefServerImpl::OnWebSocketRequest(
476     int connection_id,
477     const net::HttpServerRequestInfo& request_info) {
478   CEF_REQUIRE_HT();
479 
480   ConnectionInfo* info = GetConnectionInfo(connection_id);
481   DCHECK(info);
482   if (!info)
483     return;
484 
485   DCHECK(!info->is_websocket);
486   info->is_websocket = true;
487   info->is_websocket_pending = true;
488 
489   // Will eventually result in a call to ContinueWebSocketRequest.
490   CefRefPtr<CefCallback> callback =
491       new AcceptWebSocketCallback(this, connection_id, request_info);
492   handler_->OnWebSocketRequest(
493       this, connection_id, request_info.peer.ToString(),
494       CreateRequest(address_, request_info, true), callback);
495 }
496 
OnWebSocketMessage(int connection_id,std::string data)497 void CefServerImpl::OnWebSocketMessage(int connection_id, std::string data) {
498   CEF_REQUIRE_HT();
499 
500   ConnectionInfo* info = GetConnectionInfo(connection_id);
501   if (!info)
502     return;
503 
504   DCHECK(info->is_websocket);
505   DCHECK(!info->is_websocket_pending);
506 
507   handler_->OnWebSocketMessage(this, connection_id, data.data(), data.size());
508 }
509 
OnClose(int connection_id)510 void CefServerImpl::OnClose(int connection_id) {
511   CEF_REQUIRE_HT();
512 
513   RemoveConnectionInfo(connection_id);
514   handler_->OnClientDisconnected(this, connection_id);
515 }
516 
StartOnUIThread(const std::string & address,uint16 port,int backlog)517 void CefServerImpl::StartOnUIThread(const std::string& address,
518                                     uint16 port,
519                                     int backlog) {
520   CEF_REQUIRE_UIT();
521   DCHECK(!thread_);
522 
523   std::unique_ptr<base::Thread> thread(
524       new base::Thread(base::StringPrintf("%s:%d", address.c_str(), port)));
525   base::Thread::Options options;
526   options.message_pump_type = base::MessagePumpType::IO;
527   if (thread->StartWithOptions(std::move(options))) {
528     // Add a reference that will be released in ShutdownOnUIThread().
529     AddRef();
530 
531     thread_ = std::move(thread);
532     task_runner_ = thread_->task_runner();
533 
534     CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::StartOnHandlerThread, this,
535                                     address, port, backlog));
536   }
537 }
538 
StartOnHandlerThread(const std::string & address,uint16 port,int backlog)539 void CefServerImpl::StartOnHandlerThread(const std::string& address,
540                                          uint16 port,
541                                          int backlog) {
542   CEF_REQUIRE_HT();
543 
544   std::unique_ptr<net::ServerSocket> socket(
545       new net::TCPServerSocket(nullptr, net::NetLogSource()));
546   if (socket->ListenWithAddressAndPort(address, port, backlog) == net::OK) {
547     server_.reset(new net::HttpServer(std::move(socket), this));
548 
549     net::IPEndPoint address;
550     if (server_->GetLocalAddress(&address) == net::OK)
551       address_ = address.ToString();
552   }
553 
554   handler_->OnServerCreated(this);
555 
556   if (!server_) {
557     // Server failed to start.
558     handler_->OnServerDestroyed(this);
559 
560     CEF_POST_TASK(CEF_UIT,
561                   base::BindOnce(&CefServerImpl::ShutdownOnUIThread, this));
562   }
563 }
564 
ShutdownOnHandlerThread()565 void CefServerImpl::ShutdownOnHandlerThread() {
566   CEF_REQUIRE_HT();
567 
568   if (server_) {
569     // Stop the server.
570     server_.reset();
571 
572     if (!connection_info_map_.empty()) {
573       // Clear |connection_info_map_| first so any calls from
574       // OnClientDisconnected will fail as expected.
575       ConnectionInfoMap temp_map;
576       temp_map.swap(connection_info_map_);
577 
578       // OnClose won't be called for clients that are connected when the server
579       // shuts down, so send the disconnected notification here.
580       ConnectionInfoMap::const_iterator it = temp_map.begin();
581       for (; it != temp_map.end(); ++it) {
582         handler_->OnClientDisconnected(this, it->first);
583       }
584     }
585 
586     handler_->OnServerDestroyed(this);
587   }
588 
589   CEF_POST_TASK(CEF_UIT,
590                 base::BindOnce(&CefServerImpl::ShutdownOnUIThread, this));
591 }
592 
ShutdownOnUIThread()593 void CefServerImpl::ShutdownOnUIThread() {
594   CEF_REQUIRE_UIT();
595 
596   handler_ = nullptr;
597 
598   if (thread_) {
599     // Stop the handler thread as a background task so the UI thread isn't
600     // blocked.
601     auto task = base::BindOnce(
602         [](std::unique_ptr<base::Thread> thread) {
603           // Calling PlatformThread::Join() on the UI thread is otherwise
604           // disallowed.
605           base::ScopedAllowBaseSyncPrimitivesForTesting
606               scoped_allow_sync_primitives;
607           thread.reset();
608         },
609         std::move(thread_));
610 
611     // Make sure the task is executed on shutdown. Otherwise, |thread| might
612     // be released outside of the correct scope.
613     base::ThreadPool::PostTask(
614         FROM_HERE,
615         {base::TaskPriority::BEST_EFFORT,
616          base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()},
617         std::move(task));
618 
619     // Release the reference that was added in StartupOnUIThread().
620     Release();
621   }
622 }
623 
ValidateServer() const624 bool CefServerImpl::ValidateServer() const {
625   CEF_REQUIRE_HT();
626   if (!server_) {
627     LOG(ERROR) << "Server is not running";
628     return false;
629   }
630   return true;
631 }
632 
CreateConnectionInfo(int connection_id)633 CefServerImpl::ConnectionInfo* CefServerImpl::CreateConnectionInfo(
634     int connection_id) {
635   CEF_REQUIRE_HT();
636 
637 #if DCHECK_IS_ON()
638   ConnectionInfoMap::const_iterator it =
639       connection_info_map_.find(connection_id);
640   DCHECK(it == connection_info_map_.end());
641 #endif
642 
643   ConnectionInfo* info = new ConnectionInfo();
644   connection_info_map_.insert(
645       std::make_pair(connection_id, base::WrapUnique(info)));
646   return info;
647 }
648 
GetConnectionInfo(int connection_id) const649 CefServerImpl::ConnectionInfo* CefServerImpl::GetConnectionInfo(
650     int connection_id) const {
651   CEF_REQUIRE_HT();
652   ConnectionInfoMap::const_iterator it =
653       connection_info_map_.find(connection_id);
654   if (it != connection_info_map_.end())
655     return it->second.get();
656 
657   LOG(ERROR) << "Invalid connection_id " << connection_id;
658   return nullptr;
659 }
660 
RemoveConnectionInfo(int connection_id)661 void CefServerImpl::RemoveConnectionInfo(int connection_id) {
662   CEF_REQUIRE_HT();
663   ConnectionInfoMap::iterator it = connection_info_map_.find(connection_id);
664   DCHECK(it != connection_info_map_.end());
665   if (it != connection_info_map_.end())
666     connection_info_map_.erase(it);
667 }
668 
CurrentlyOnHandlerThread() const669 bool CefServerImpl::CurrentlyOnHandlerThread() const {
670   return task_runner_ && task_runner_->BelongsToCurrentThread();
671 }
672