@@ -200,7 +200,7 @@ namespace
200
200
}
201
201
202
202
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);
204
204
205
205
};
206
206
@@ -333,20 +333,41 @@ class asio_server_connection
333
333
std::unique_ptr<boost::asio::ssl::context> m_ssl_context;
334
334
std::unique_ptr<ssl_stream> m_ssl_stream;
335
335
336
- public:
337
336
asio_server_connection (std::unique_ptr<boost::asio::ip::tcp::socket> socket, http_linux_server* server, hostport_listener* parent)
338
337
: m_socket(std::move(socket))
339
338
, m_request_buf()
340
339
, m_response_buf()
341
340
, m_p_server(server)
342
341
, m_p_parent(parent)
343
342
, m_close(false )
343
+ , m_chunked(false )
344
344
, m_refs(1 )
345
345
{
346
346
}
347
347
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 ()
349
362
{
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
+
350
371
if (is_https)
351
372
{
352
373
m_ssl_context = make_unique<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
@@ -360,11 +381,14 @@ class asio_server_connection
360
381
{
361
382
(will_deref_and_erase_t )this ->start_request_response ();
362
383
});
363
- return will_deref_and_erase_t {};
384
+ unique_reference.release ();
385
+ return will_erase_from_parent_t {};
364
386
}
365
387
else
366
388
{
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 {};
368
392
}
369
393
}
370
394
@@ -385,7 +409,7 @@ class asio_server_connection
385
409
will_deref_and_erase_t dispatch_request_to_listener ();
386
410
will_erase_from_parent_t do_response ()
387
411
{
388
- ++m_refs ;
412
+ auto unique_reference = this -> get_reference () ;
389
413
m_request.get_response ().then ([=](pplx::task<http_response> r_task)
390
414
{
391
415
http_response response;
@@ -406,11 +430,12 @@ class asio_server_connection
406
430
(will_deref_and_erase_t )this ->async_write (&asio_server_connection::handle_headers_written, response);
407
431
});
408
432
});
433
+ unique_reference.release ();
409
434
return will_erase_from_parent_t {};
410
435
}
411
436
will_erase_from_parent_t do_bad_response ()
412
437
{
413
- ++m_refs ;
438
+ auto unique_reference = this -> get_reference () ;
414
439
m_request.get_response ().then ([=](pplx::task<http_response> r_task)
415
440
{
416
441
http_response response;
@@ -428,6 +453,7 @@ class asio_server_connection
428
453
429
454
(will_deref_and_erase_t )async_write (&asio_server_connection::handle_headers_written, response);
430
455
});
456
+ unique_reference.release ();
431
457
return will_erase_from_parent_t {};
432
458
}
433
459
@@ -495,10 +521,13 @@ void hostport_listener::start()
495
521
m_acceptor->listen (0 != m_backlog ? m_backlog : socket_base::max_connections);
496
522
497
523
auto socket = new ip::tcp::socket (service);
524
+ std::unique_ptr<ip::tcp::socket> usocket (socket);
498
525
m_acceptor->async_accept (*socket, [this , socket](const boost::system::error_code& ec)
499
526
{
500
- this ->on_accept (socket, ec);
527
+ std::unique_ptr<ip::tcp::socket> usocket (socket);
528
+ this ->on_accept (std::move (usocket), ec);
501
529
});
530
+ usocket.release ();
502
531
}
503
532
504
533
void asio_server_connection::close ()
@@ -538,30 +567,53 @@ will_deref_and_erase_t asio_server_connection::start_request_response()
538
567
return will_deref_and_erase_t {};
539
568
}
540
569
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)
542
571
{
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);
544
579
580
+ // Handle successful accept
545
581
if (!ec)
546
582
{
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 );
548
584
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
554
591
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&)
556
597
{
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 ());
563
602
}
564
603
}
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
+ }
565
617
}
566
618
567
619
will_deref_and_erase_t asio_server_connection::handle_http_line (const boost::system::error_code& ec)
0 commit comments