Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle chunked payload in connection.hpp #106

Merged
merged 11 commits into from
Oct 10, 2024
71 changes: 51 additions & 20 deletions CRUD/service/connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
#include "reply.hpp"
#include "request.hpp"
#include "request_parser.hpp"
namespace http {
namespace server {
#include "data_read_result.hpp"

namespace http::server {
template<class> class connection_manager;

/// Represents a single connection from a client.
Expand Down Expand Up @@ -66,25 +66,23 @@ class connection
{
auto self(this->shared_from_this());
socket_.async_read_some(boost::asio::buffer(buffer_),
[this](boost::system::error_code ec, std::size_t bytes_transferred)
[this, self](boost::system::error_code ec, std::size_t bytes_transferred)
{
if (!ec)

if (!ec) [[likely]]
{
request_parser::result_type result;
char * data;
char * data = nullptr;
std::tie(result, data) = request_parser_.parse(
request_, buffer_.data(), buffer_.data() + bytes_transferred);
auto itr = std::find_if( request_.headers.begin(),
request_.headers.end(),
[](const header &h) { return h.name == "content-length" ; }
) ;
if ( itr != request_.headers.end()) {
request_.data = std::string(data, boost::lexical_cast<long>(itr->value)) ;
}
if (result == request_parser::good)

if (result == request_parser::good) [[likely]]
{
request_handler_.handle_request(request_, reply_);
do_write();
auto status = handle_request_if(data, bytes_transferred);
if (status == data_read_result::complete) {
request_handler_.handle_request(request_, reply_);
do_write();
}
}
else if (result == request_parser::bad)
{
Expand Down Expand Up @@ -124,8 +122,41 @@ class connection
}
});
}

/// Socket for the connection.

data_read_result handle_request_if(char * const data, std::size_t bytes_transferred) {
static constexpr auto is_content_length = [](const header &h) noexcept { return h.name == "content-length" ; };

data_read_result completion_status{data_read_result::complete};
if (data != nullptr) {
auto itr = find_if(begin(request_.headers), end(request_.headers), is_content_length);

if (itr != end(request_.headers)) {
auto received_data_size = std::distance(data, buffer_.data() + bytes_transferred);
auto content_length_value = boost::lexical_cast<long>(itr->value);
request_.data = std::string(data, received_data_size);
if (received_data_size < content_length_value) {
completion_status = data_read_result::indeterminate;
request_.data.resize(content_length_value);
auto left_over_size = content_length_value - received_data_size;
auto end_data_ptr = request_.data.data() + received_data_size;
auto left_over_buffer = boost::asio::buffer(end_data_ptr, left_over_size);
auto self{this->shared_from_this()}; //make sure connection is alive while lambda is in progress
boost::asio::async_read(socket_, left_over_buffer, boost::asio::transfer_exactly(left_over_size),
[this, self](boost::system::error_code ec, std::size_t) {
if (!ec) [[likely]] {
request_handler_.handle_request(request_, reply_);
do_write();
} else if (ec != boost::asio::error::operation_aborted) {
connection_manager_.stop(this->shared_from_this());
}
});
}
}
}
return completion_status;
}

/// Socket for the persistent_connection.
boost::asio::ip::tcp::socket socket_;

/// The manager for this connection.
Expand All @@ -148,8 +179,8 @@ class connection
};


} // namespace server
} // namespace http
} // namespace http::server


#endif // HTTP_CONNECTION_HPP

11 changes: 11 additions & 0 deletions CRUD/service/data_read_result.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//
// Created by VanillaRTB on 10/9/24.
//
#pragma once
#ifndef VANILLA_RTB_DATA_READ_RESULT_HPP
#define VANILLA_RTB_DATA_READ_RESULT_HPP
/// Result of data read.
namespace http::server {
enum data_read_result { complete, indeterminate };
}
#endif // VANILLA_RTB_DATA_READ_RESULT_HPP
4 changes: 1 addition & 3 deletions CRUD/service/persistent_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,12 @@
#include "reply.hpp"
#include "request.hpp"
#include "request_parser.hpp"
#include "data_read_result.hpp"

namespace http::server {

template<class> class connection_manager;

/// Result of data read.
enum data_read_result { complete, indeterminate };

/// Represents a single connection from a client.
template <typename request_handler_type>
class persistent_connection
Expand Down