http_send_op.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. */
  10. #ifndef __ASIO2_HTTP_SEND_OP_HPP__
  11. #define __ASIO2_HTTP_SEND_OP_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <memory>
  16. #include <future>
  17. #include <utility>
  18. #include <string_view>
  19. #include <asio2/external/asio.hpp>
  20. #include <asio2/external/beast.hpp>
  21. #include <asio2/base/error.hpp>
  22. #include <asio2/http/detail/http_util.hpp>
  23. #include <asio2/http/request.hpp>
  24. #include <asio2/http/response.hpp>
  25. namespace asio2::detail
  26. {
  27. template<class derived_t, class args_t>
  28. class http_send_op
  29. {
  30. public:
  31. using body_type = typename args_t::body_t;
  32. using buffer_type = typename args_t::buffer_t;
  33. /**
  34. * @brief constructor
  35. */
  36. http_send_op() noexcept {}
  37. /**
  38. * @brief destructor
  39. */
  40. ~http_send_op() = default;
  41. protected:
  42. template<bool isRequest, class Body, class Fields>
  43. inline void _check_http_message(http::message<isRequest, Body, Fields>& msg)
  44. {
  45. // https://datatracker.ietf.org/doc/html/rfc2616#section-14.13
  46. // If an http message header don't has neither "Content-Length" nor "Transfer-Encoding"(chunk)
  47. // Then the receiver may not be able to parse the http message normally.
  48. if (!msg.chunked())
  49. {
  50. if (msg.find(http::field::content_length) == msg.end())
  51. {
  52. http::try_prepare_payload(msg);
  53. }
  54. }
  55. }
  56. protected:
  57. template<class Data, class Callback>
  58. inline bool _http_send(Data& data, Callback&& callback)
  59. {
  60. derived_t& derive = static_cast<derived_t&>(*this);
  61. return derive._tcp_send(data, std::forward<Callback>(callback));
  62. }
  63. template<bool isRequest, class Body, class Fields, class Callback>
  64. inline bool _http_send(http::message<isRequest, Body, Fields>& data, Callback&& callback)
  65. {
  66. derived_t& derive = static_cast<derived_t&>(*this);
  67. derive._check_http_message(data);
  68. #if defined(_DEBUG) || defined(DEBUG)
  69. ASIO2_ASSERT(derive.post_send_counter_.load() == 0);
  70. derive.post_send_counter_++;
  71. #endif
  72. http::async_write(derive.stream(), data, make_allocator(derive.wallocator(),
  73. [&derive, callback = std::forward<Callback>(callback)]
  74. (const error_code& ec, std::size_t bytes_sent) mutable
  75. {
  76. #if defined(_DEBUG) || defined(DEBUG)
  77. derive.post_send_counter_--;
  78. #endif
  79. set_last_error(ec);
  80. callback(ec, bytes_sent);
  81. if (ec)
  82. {
  83. // must stop, otherwise re-sending will cause body confusion
  84. if (derive.state_ == state_t::started)
  85. {
  86. derive._do_disconnect(ec, derive.selfptr());
  87. }
  88. }
  89. }));
  90. return true;
  91. }
  92. template<class Body, class Fields, class Callback>
  93. inline bool _http_send(detail::http_request_impl_t<Body, Fields>& data, Callback&& callback)
  94. {
  95. derived_t& derive = static_cast<derived_t&>(*this);
  96. derive._check_http_message(data.base());
  97. #if defined(_DEBUG) || defined(DEBUG)
  98. ASIO2_ASSERT(derive.post_send_counter_.load() == 0);
  99. derive.post_send_counter_++;
  100. #endif
  101. http::async_write(derive.stream(), data.base(), make_allocator(derive.wallocator(),
  102. [&derive, callback = std::forward<Callback>(callback)]
  103. (const error_code& ec, std::size_t bytes_sent) mutable
  104. {
  105. #if defined(_DEBUG) || defined(DEBUG)
  106. derive.post_send_counter_--;
  107. #endif
  108. set_last_error(ec);
  109. callback(ec, bytes_sent);
  110. if (ec)
  111. {
  112. // must stop, otherwise re-sending will cause body confusion
  113. if (derive.state_ == state_t::started)
  114. {
  115. derive._do_disconnect(ec, derive.selfptr());
  116. }
  117. }
  118. }));
  119. return true;
  120. }
  121. template<class Body, class Fields, class Callback>
  122. inline bool _http_send(detail::http_response_impl_t<Body, Fields>& data, Callback&& callback)
  123. {
  124. derived_t& derive = static_cast<derived_t&>(*this);
  125. derive._check_http_message(data.base());
  126. #if defined(_DEBUG) || defined(DEBUG)
  127. ASIO2_ASSERT(derive.post_send_counter_.load() == 0);
  128. derive.post_send_counter_++;
  129. #endif
  130. http::async_write(derive.stream(), data.base(), make_allocator(derive.wallocator(),
  131. [&derive, callback = std::forward<Callback>(callback)]
  132. (const error_code& ec, std::size_t bytes_sent) mutable
  133. {
  134. #if defined(_DEBUG) || defined(DEBUG)
  135. derive.post_send_counter_--;
  136. #endif
  137. set_last_error(ec);
  138. callback(ec, bytes_sent);
  139. if (ec)
  140. {
  141. // must stop, otherwise re-sending will cause body confusion
  142. if (derive.state_ == state_t::started)
  143. {
  144. derive._do_disconnect(ec, derive.selfptr());
  145. }
  146. }
  147. }));
  148. return true;
  149. }
  150. protected:
  151. };
  152. }
  153. #endif // !__ASIO2_HTTP_SEND_OP_HPP__