@@ -200,7 +200,7 @@ namespace
200200 }
201201
202202 private:
203- void on_accept (boost::asio::ip::tcp::socket* socket, const boost::system::error_code& ec);
203+ void on_accept (std::unique_ptr< boost::asio::ip::tcp::socket> socket, const boost::system::error_code& ec);
204204
205205 };
206206
@@ -333,20 +333,41 @@ class asio_server_connection
333333 std::unique_ptr<boost::asio::ssl::context> m_ssl_context;
334334 std::unique_ptr<ssl_stream> m_ssl_stream;
335335
336- public:
337336 asio_server_connection (std::unique_ptr<boost::asio::ip::tcp::socket> socket, http_linux_server* server, hostport_listener* parent)
338337 : m_socket(std::move(socket))
339338 , m_request_buf()
340339 , m_response_buf()
341340 , m_p_server(server)
342341 , m_p_parent(parent)
343342 , m_close(false )
343+ , m_chunked(false )
344344 , m_refs(1 )
345345 {
346346 }
347347
348- will_deref_and_erase_t start (bool is_https, const std::function<void (boost::asio::ssl::context&)>& ssl_context_callback)
348+ struct Dereferencer
349+ {
350+ void operator ()(asio_server_connection* conn) const { conn->deref (); }
351+ };
352+
353+ public:
354+ using refcount_ptr = std::unique_ptr<asio_server_connection, Dereferencer>;
355+
356+ static refcount_ptr create (std::unique_ptr<boost::asio::ip::tcp::socket> socket, http_linux_server* server, hostport_listener* parent)
357+ {
358+ return refcount_ptr (new asio_server_connection (std::move (socket), server, parent));
359+ }
360+
361+ refcount_ptr get_reference ()
349362 {
363+ ++m_refs;
364+ return refcount_ptr (this );
365+ }
366+
367+ will_erase_from_parent_t start_connection (bool is_https, const std::function<void (boost::asio::ssl::context&)>& ssl_context_callback)
368+ {
369+ auto unique_reference = this ->get_reference ();
370+
350371 if (is_https)
351372 {
352373 m_ssl_context = make_unique<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
@@ -360,11 +381,14 @@ class asio_server_connection
360381 {
361382 (will_deref_and_erase_t )this ->start_request_response ();
362383 });
363- return will_deref_and_erase_t {};
384+ unique_reference.release ();
385+ return will_erase_from_parent_t {};
364386 }
365387 else
366388 {
367- return start_request_response ();
389+ (will_deref_and_erase_t )start_request_response ();
390+ unique_reference.release ();
391+ return will_erase_from_parent_t {};
368392 }
369393 }
370394
@@ -385,7 +409,7 @@ class asio_server_connection
385409 will_deref_and_erase_t dispatch_request_to_listener ();
386410 will_erase_from_parent_t do_response ()
387411 {
388- ++m_refs ;
412+ auto unique_reference = this -> get_reference () ;
389413 m_request.get_response ().then ([=](pplx::task<http_response> r_task)
390414 {
391415 http_response response;
@@ -406,11 +430,12 @@ class asio_server_connection
406430 (will_deref_and_erase_t )this ->async_write (&asio_server_connection::handle_headers_written, response);
407431 });
408432 });
433+ unique_reference.release ();
409434 return will_erase_from_parent_t {};
410435 }
411436 will_erase_from_parent_t do_bad_response ()
412437 {
413- ++m_refs ;
438+ auto unique_reference = this -> get_reference () ;
414439 m_request.get_response ().then ([=](pplx::task<http_response> r_task)
415440 {
416441 http_response response;
@@ -428,6 +453,7 @@ class asio_server_connection
428453
429454 (will_deref_and_erase_t )async_write (&asio_server_connection::handle_headers_written, response);
430455 });
456+ unique_reference.release ();
431457 return will_erase_from_parent_t {};
432458 }
433459
@@ -495,10 +521,13 @@ void hostport_listener::start()
495521 m_acceptor->listen (0 != m_backlog ? m_backlog : socket_base::max_connections);
496522
497523 auto socket = new ip::tcp::socket (service);
524+ std::unique_ptr<ip::tcp::socket> usocket (socket);
498525 m_acceptor->async_accept (*socket, [this , socket](const boost::system::error_code& ec)
499526 {
500- this ->on_accept (socket, ec);
527+ std::unique_ptr<ip::tcp::socket> usocket (socket);
528+ this ->on_accept (std::move (usocket), ec);
501529 });
530+ usocket.release ();
502531}
503532
504533void asio_server_connection::close ()
@@ -538,30 +567,53 @@ will_deref_and_erase_t asio_server_connection::start_request_response()
538567 return will_deref_and_erase_t {};
539568}
540569
541- void hostport_listener::on_accept (ip::tcp::socket* socket, const boost::system::error_code& ec)
570+ void hostport_listener::on_accept (std::unique_ptr< ip::tcp::socket> socket, const boost::system::error_code& ec)
542571{
543- std::unique_ptr<ip::tcp::socket> usocket (std::move (socket));
572+ // Listener closed
573+ if (ec == boost::asio::error::operation_aborted)
574+ {
575+ return ;
576+ }
577+
578+ std::lock_guard<std::mutex> lock (m_connections_lock);
544579
580+ // Handle successful accept
545581 if (!ec)
546582 {
547- auto conn = new asio_server_connection (std::move (usocket ), m_p_server, this );
583+ auto conn = asio_server_connection::create (std::move (socket ), m_p_server, this );
548584
549- std::lock_guard<std::mutex> lock (m_connections_lock);
550- m_connections.insert (conn);
551- conn->start (m_is_https, m_ssl_context_callback);
552- if (m_connections.size () == 1 )
553- m_all_connections_complete.reset ();
585+ m_connections.insert (conn.get ());
586+ try
587+ {
588+ (will_erase_from_parent_t )conn->start_connection (m_is_https, m_ssl_context_callback);
589+ // at this point an asynchronous task has been launched which will call
590+ // m_connections.erase(conn.get()) eventually
554591
555- if (m_acceptor)
592+ // the following cannot throw
593+ if (m_connections.size () == 1 )
594+ m_all_connections_complete.reset ();
595+ }
596+ catch (boost::system::system_error&)
556597 {
557- // spin off another async accept
558- auto newSocket = new ip::tcp::socket (crossplat::threadpool::shared_instance ().service ());
559- m_acceptor->async_accept (*newSocket, [this , newSocket](const boost::system::error_code& ec)
560- {
561- this ->on_accept (newSocket, ec);
562- });
598+ // boost ssl apis throw boost::system::system_error.
599+ // Exception indicates something went wrong setting ssl context.
600+ // Drop connection and continue handling other connections.
601+ m_connections.erase (conn.get ());
563602 }
564603 }
604+
605+ if (m_acceptor)
606+ {
607+ // spin off another async accept
608+ auto newSocket = new ip::tcp::socket (crossplat::threadpool::shared_instance ().service ());
609+ std::unique_ptr<ip::tcp::socket> usocket (newSocket);
610+ m_acceptor->async_accept (*newSocket, [this , newSocket](const boost::system::error_code& ec)
611+ {
612+ std::unique_ptr<ip::tcp::socket> usocket (newSocket);
613+ this ->on_accept (std::move (usocket), ec);
614+ });
615+ usocket.release ();
616+ }
565617}
566618
567619will_deref_and_erase_t asio_server_connection::handle_http_line (const boost::system::error_code& ec)
0 commit comments