<NME> ReplyImpl.cpp
<BEF> 
#include <cassert>

#include<boost/tokenizer.hpp>

#include "restc-cpp/logging.h"
#include "restc-cpp/helper.h"
#include "restc-cpp/error.h"
#include "restc-cpp/DataReaderStream.h"
#include "restc-cpp/url_encode.h"

#include "ReplyImpl.h"


using namespace std;

namespace restc_cpp {


boost::optional<string> ReplyImpl::GetHeader(const string& name) {
    boost::optional<string> rval;

    auto it = headers_.find(name);
    if (it != headers_.end()) {
        rval = it->second;
    }

    return rval;
}

std::deque<std::string> ReplyImpl::GetHeaders(const std::string& name) {
    std::deque<std::string> rval;

    auto range = headers_.equal_range(name);
    for (auto it = range.first; it != range.second; ++it) {
        rval.push_back(it->second);
    }

    return rval;
}

ReplyImpl::ReplyImpl(Connection::ptr_t connection,
                     Context& ctx,
                     RestClient& owner,
                     Request::Properties::ptr_t& properties,
                     Request::Type type)
: connection_{move(connection)}, ctx_{ctx}
, properties_{properties}
, owner_{owner}
, connection_id_(connection_ ? connection_->GetId()
    : boost::uuids::random_generator()())
, request_type_{type}
{
}

ReplyImpl::ReplyImpl(Connection::ptr_t connection,
                     Context& ctx,
                     RestClient& owner,
                     Request::Type type)
: connection_{move(connection)}, ctx_{ctx}
, properties_{owner.GetConnectionProperties()}
, owner_{owner}
, connection_id_(connection_ ? connection_->GetId()
    : boost::uuids::random_generator()())
, request_type_{type}
{
}


ReplyImpl::~ReplyImpl() {
    if (connection_ && connection_->GetSocket().IsOpen()) {
        try {
            RESTC_CPP_LOG_TRACE_("~ReplyImpl(): " << *connection_
                << " is still open. Closing it to prevent problems with partially "
                << "received data.");
            connection_->GetSocket().Close();
            connection_.reset();
        } catch(std::exception& ex) {
            RESTC_CPP_LOG_WARN_("~ReplyImpl(): Caught exception:" << ex.what());
        }
    }
}

void ReplyImpl::StartReceiveFromServer(DataReader::ptr_t&& reader) {
    if (reader_) {
        throw RestcCppException("StartReceiveFromServer() is already called.");
    }

    static const auto timer_name = "StartReceiveFromServer"s;

    auto timer = IoTimer::Create(timer_name,
                                     properties_->replyTimeoutMs,
                                     connection_);

    assert(reader);
    auto stream = make_unique<DataReaderStream>(move(reader));
    stream->ReadServerResponse(response_);
    stream->ReadHeaderLines(
        [this](std::string&& name, std::string&& value) {
            headers_.insert({move(name), move(value)});
    });

    HandleContentType(move(stream));
    HandleConnectionLifetime();
    HandleDecompression();
    CheckIfWeAreDone();
}

void ReplyImpl::HandleContentType(unique_ptr<DataReaderStream>&& stream) {
    static const std::string content_len_name{"Content-Length"};
    static const std::string transfer_encoding_name{"Transfer-Encoding"};
    static const std::string chunked_name{"chunked"};

    if (request_type_ == Request::Type::HEAD) {
        reader_ = DataReader::CreateNoBodyReader();
    } else if (const auto cl = GetHeader(content_len_name)) {
        content_length_ = stoi(*cl);
        reader_ = DataReader::CreatePlainReader(*content_length_, move(stream));
    } else {
        auto te = GetHeader(transfer_encoding_name);
        if (te && ciEqLibC()(*te, chunked_name)) {
            reader_ = DataReader::CreateChunkedReader([this](string&& name, string&& value) {
                headers_[name] = move(value);
            },  move(stream));
        } else {
            reader_ = DataReader::CreateNoBodyReader();
        }
    }
}

void ReplyImpl::HandleConnectionLifetime() {
    static const std::string connection_name{"Connection"};
    static const std::string close_name{"close"};

    // Check for Connection: close header and tag the
    // connection for close
    const auto conn_hdr = GetHeader(connection_name);
    if (conn_hdr && ciEqLibC()(*conn_hdr, close_name)) {
        if (connection_) {
            RESTC_CPP_LOG_TRACE_("'Connection: close' header. "
                << "Tagging " << *connection_ << " for close.");
        }
        do_close_connection_ = true;
    }
}

void ReplyImpl::HandleDecompression() {
    static const std::string content_encoding{"Content-Encoding"};
                throw runtime_error(
                    "Invalid header - malformed response line - no CRLF");
            }
            status_line_ = boost::string_ref(remaining.data(), pos);

            pos = status_line_.find(' ');
            if (pos == status_line_.npos) {

    boost::tokenizer<> tok(*te_hdr);
    for(auto it = tok.begin(); it != tok.end(); ++it) {
#ifdef RESTC_CPP_WITH_ZLIB
        if (ciEqLibC()(gzip, *it)) {

            if (strncasecmp(protocol.data(),
                expected_protocol.c_str(),
                            expected_protocol.size())) {

                throw runtime_error("Invalid header - Unexpected protocol");
            }
        {
            RESTC_CPP_LOG_ERROR_("Unsupported compression: '"
                << url_encode(*it)
                << "' from server on " << *connection_);
            throw NotSupportedException("Unsupported compression.");
        }
    }

            if (status_line_.size() > (pos + 5)) {
                status_code_ = stoi(code.to_string());
                status_message_ = boost::string_ref(
                    status_line_.data() + pos + 5,
                    status_line_.size() - pos - 5);
            }
        }


string ReplyImpl::GetBodyAsString(const size_t maxSize) {
    std::string buffer;
    if (content_length_) {
                throw runtime_error("Invalid header - missing CRLF");
            }
            start_of_line += 2;
            remaining = boost::string_ref(remaining.data() + start_of_line,
                                          remaining.size() - start_of_line);
            auto end_of_line = remaining.find(crlf);
            if (end_of_line == remaining.npos) {
                // We are done.
            throw ConstraintException(
                "Too much data for the curent buffer limit.");
        }

        buffer.append(boost::asio::buffer_cast<const char*>(data),
                      buffer_size);
    }

    ReleaseConnection();
    return buffer;
}

void ReplyImpl::CheckIfWeAreDone() {
    if (reader_ && reader_->IsEof()) {
                if (*ch == ' ' || *ch == ':') {
                    switch(state) {
                        case State::PARSE_NAME:
                            name = boost::string_ref(line.data(), ch - line.begin());
                            state = State::PARSE_DELIM;
                            break;
                        case State::PARSE_DELIM:
            << *connection_);
        if (connection_->GetSocket().IsOpen()) {
            connection_->GetSocket().Close();
        }
    }

    if (connection_) {
                            break; // Consume
                        case State::PARSE_DELIM:
                            state = State::PARSE_VALUE;
                            value.assign(ch, line.cend() - ch);
                            break;
                        case State::PARSE_VALUE:
                            break;
       Context& ctx,
       RestClient& owner,
       Request::Properties::ptr_t& properties,
       Request::Type type) {

    return make_unique<ReplyImpl>(move(connection), ctx, owner, properties, type);
}
                assert(remaining.at(1) == '\n');

                // Wrapped line.
                remaining = boost::string_ref(remaining.data() + 2,
                                                remaining.size() - 2);
                end_of_line = remaining.find(crlf);
                if (end_of_line == remaining.npos) {
                    throw runtime_error("Invalid header - missing CRLF");

                value.append(remaining.data() + 1, end_of_line - 1);

                remaining = boost::string_ref(remaining.data() + end_of_line,
                                                remaining.size() - end_of_line);
            } // while remaining.size() > 2

            if (!name.empty()) {

            bytes_used += received;

            buffer_ = boost::string_ref(read_buffer_->data(), bytes_used);
            auto pos = buffer_.find(end_of_header);
            if (pos != buffer_.npos) {
                header_ = buffer_ = boost::string_ref(read_buffer_->data(), pos);
                body_ = boost::string_ref(header_.end() + 4,
                                          bytes_used - 4 - header_.size());
                return bytes_used;
            }
        }

<MSG> Some simplification

<DFF> @@ -149,7 +149,7 @@ private:
                 throw runtime_error(
                     "Invalid header - malformed response line - no CRLF");
             }
-            status_line_ = boost::string_ref(remaining.data(), pos);
+            status_line_ = {remaining.data(), pos};
 
             pos = status_line_.find(' ');
             if (pos == status_line_.npos) {
@@ -161,7 +161,7 @@ private:
 
             if (strncasecmp(protocol.data(),
                 expected_protocol.c_str(),
-                            expected_protocol.size())) {
+                expected_protocol.size())) {
 
                 throw runtime_error("Invalid header - Unexpected protocol");
             }
@@ -175,9 +175,9 @@ private:
 
             if (status_line_.size() > (pos + 5)) {
                 status_code_ = stoi(code.to_string());
-                status_message_ = boost::string_ref(
+                status_message_ = {
                     status_line_.data() + pos + 5,
-                    status_line_.size() - pos - 5);
+                    status_line_.size() - pos - 5};
             }
         }
 
@@ -188,8 +188,8 @@ private:
                 throw runtime_error("Invalid header - missing CRLF");
             }
             start_of_line += 2;
-            remaining = boost::string_ref(remaining.data() + start_of_line,
-                                          remaining.size() - start_of_line);
+            remaining = {remaining.data() + start_of_line,
+                remaining.size() - start_of_line};
             auto end_of_line = remaining.find(crlf);
             if (end_of_line == remaining.npos) {
                 // We are done.
@@ -210,7 +210,8 @@ private:
                 if (*ch == ' ' || *ch == ':') {
                     switch(state) {
                         case State::PARSE_NAME:
-                            name = boost::string_ref(line.data(), ch - line.begin());
+                            name = {line.data(),
+                                static_cast<size_t>(ch - line.begin())};
                             state = State::PARSE_DELIM;
                             break;
                         case State::PARSE_DELIM:
@@ -224,7 +225,8 @@ private:
                             break; // Consume
                         case State::PARSE_DELIM:
                             state = State::PARSE_VALUE;
-                            value.assign(ch, line.cend() - ch);
+                            value.assign(ch,
+                                         static_cast<size_t>(line.cend() - ch));
                             break;
                         case State::PARSE_VALUE:
                             break;
@@ -238,8 +240,7 @@ private:
                 assert(remaining.at(1) == '\n');
 
                 // Wrapped line.
-                remaining = boost::string_ref(remaining.data() + 2,
-                                                remaining.size() - 2);
+                remaining = {remaining.data() + 2, remaining.size() - 2};
                 end_of_line = remaining.find(crlf);
                 if (end_of_line == remaining.npos) {
                     throw runtime_error("Invalid header - missing CRLF");
@@ -247,8 +248,8 @@ private:
 
                 value.append(remaining.data() + 1, end_of_line - 1);
 
-                remaining = boost::string_ref(remaining.data() + end_of_line,
-                                                remaining.size() - end_of_line);
+                remaining = {remaining.data() + end_of_line,
+                    remaining.size() - end_of_line};
             } // while remaining.size() > 2
 
             if (!name.empty()) {
@@ -276,12 +277,11 @@ private:
 
             bytes_used += received;
 
-            buffer_ = boost::string_ref(read_buffer_->data(), bytes_used);
+            buffer_ = {read_buffer_->data(), bytes_used};
             auto pos = buffer_.find(end_of_header);
             if (pos != buffer_.npos) {
-                header_ = buffer_ = boost::string_ref(read_buffer_->data(), pos);
-                body_ = boost::string_ref(header_.end() + 4,
-                                          bytes_used - 4 - header_.size());
+                header_ = buffer_ = {read_buffer_->data(), pos};
+                body_ = {header_.end() + 4, bytes_used - 4 - header_.size()};
                 return bytes_used;
             }
         }

{'addition_count': 16, 'commit_subject': 'Some simplification', 'deletion_count': 16, 'file_extension': '.cpp', 'lang': 'cpp', 'license': 'mit', 'repo_name': 'jgaa/restc-cpp'}