connection.cc 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <asiolink/asio_wrapper.h>
  7. #include <http/connection.h>
  8. #include <http/connection_pool.h>
  9. #include <boost/bind.hpp>
  10. using namespace isc::asiolink;
  11. namespace isc {
  12. namespace http {
  13. void
  14. HttpConnection::
  15. SocketCallback::operator()(boost::system::error_code ec, size_t length) {
  16. if (ec.value() == boost::asio::error::operation_aborted) {
  17. return;
  18. }
  19. callback_(ec, length);
  20. }
  21. HttpConnection:: HttpConnection(asiolink::IOService& io_service,
  22. HttpAcceptor& acceptor,
  23. HttpConnectionPool& connection_pool,
  24. const HttpResponseCreatorPtr& response_creator,
  25. const HttpAcceptorCallback& callback,
  26. const long request_timeout)
  27. : request_timer_(io_service),
  28. request_timeout_(request_timeout),
  29. socket_(io_service),
  30. socket_callback_(boost::bind(&HttpConnection::socketReadCallback, this,
  31. _1, _2)),
  32. socket_write_callback_(boost::bind(&HttpConnection::socketWriteCallback,
  33. this, _1, _2)),
  34. acceptor_(acceptor),
  35. connection_pool_(connection_pool),
  36. response_creator_(response_creator),
  37. request_(response_creator_->createNewHttpRequest()),
  38. parser_(new HttpRequestParser(*request_)),
  39. acceptor_callback_(callback),
  40. buf_() {
  41. parser_->initModel();
  42. }
  43. HttpConnection::~HttpConnection() {
  44. close();
  45. }
  46. void
  47. HttpConnection::close() {
  48. socket_.close();
  49. }
  50. void
  51. HttpConnection::stopThisConnection() {
  52. try {
  53. connection_pool_.stop(shared_from_this());
  54. } catch (...) {
  55. }
  56. }
  57. void
  58. HttpConnection::asyncAccept() {
  59. HttpAcceptorCallback cb = boost::bind(&HttpConnection::acceptorCallback,
  60. this, _1);
  61. try {
  62. acceptor_.asyncAccept(socket_, cb);
  63. } catch (const std::exception& ex) {
  64. isc_throw(HttpConnectionError, "unable to start accepting TCP "
  65. "connections: " << ex.what());
  66. }
  67. }
  68. void
  69. HttpConnection::doRead() {
  70. try {
  71. TCPEndpoint endpoint;
  72. socket_.asyncReceive(static_cast<void*>(buf_.data()), buf_.size(),
  73. 0, &endpoint, socket_callback_);
  74. } catch (const std::exception& ex) {
  75. stopThisConnection();
  76. }
  77. }
  78. void
  79. HttpConnection::doWrite() {
  80. try {
  81. if (!output_buf_.empty()) {
  82. socket_.asyncSend(output_buf_.data(),
  83. output_buf_.length(),
  84. socket_write_callback_);
  85. } else {
  86. stopThisConnection();
  87. }
  88. } catch (const std::exception& ex) {
  89. stopThisConnection();
  90. }
  91. }
  92. void
  93. HttpConnection::asyncSendResponse(const ConstHttpResponsePtr& response) {
  94. output_buf_ = response->toString();
  95. doWrite();
  96. }
  97. void
  98. HttpConnection::acceptorCallback(const boost::system::error_code& ec) {
  99. if (!acceptor_.isOpen()) {
  100. return;
  101. }
  102. if (ec) {
  103. stopThisConnection();
  104. }
  105. acceptor_callback_(ec);
  106. if (!ec) {
  107. request_timer_.setup(boost::bind(&HttpConnection::requestTimeoutCallback, this),
  108. request_timeout_, IntervalTimer::ONE_SHOT);
  109. doRead();
  110. }
  111. }
  112. void
  113. HttpConnection::socketReadCallback(boost::system::error_code ec, size_t length) {
  114. std::string s(&buf_[0], buf_[0] + length);
  115. parser_->postBuffer(static_cast<void*>(buf_.data()), length);
  116. parser_->poll();
  117. if (parser_->needData()) {
  118. doRead();
  119. } else {
  120. try {
  121. request_->finalize();
  122. } catch (...) {
  123. }
  124. HttpResponsePtr response = response_creator_->createHttpResponse(request_);
  125. asyncSendResponse(response);
  126. }
  127. }
  128. void
  129. HttpConnection::socketWriteCallback(boost::system::error_code ec,
  130. size_t length) {
  131. if (length <= output_buf_.size()) {
  132. output_buf_.erase(0, length);
  133. doWrite();
  134. } else {
  135. output_buf_.clear();
  136. stopThisConnection();
  137. }
  138. }
  139. void
  140. HttpConnection::requestTimeoutCallback() {
  141. HttpResponsePtr response =
  142. response_creator_->createStockHttpResponse(request_,
  143. HttpStatusCode::REQUEST_TIMEOUT);
  144. asyncSendResponse(response);
  145. }
  146. } // end of namespace isc::http
  147. } // end of namespace isc