From 99d577f43a1788378a51af3753a99d8729f59706 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Thu, 3 Sep 2020 00:55:16 +0100 Subject: [PATCH] Bugfix in HttpResponse string_views are potentially wrong if raw is very small and stdlib has small string optimisation. Use unique_ptr instead to force allocations in all cases. --- src/nap/http_response.hpp | 4 ++-- src/nap/page_fetch.cpp | 40 ++++++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/nap/http_response.hpp b/src/nap/http_response.hpp index 3859ab6..4db8b81 100644 --- a/src/nap/http_response.hpp +++ b/src/nap/http_response.hpp @@ -17,7 +17,7 @@ #pragma once -#include +#include #include #include #include @@ -25,7 +25,7 @@ namespace nap { struct HttpResponse { - std::string raw; + std::unique_ptr raw; std::vector> header; std::string_view body; std::string_view http_ver; diff --git a/src/nap/page_fetch.cpp b/src/nap/page_fetch.cpp index 34118b0..e2fc270 100644 --- a/src/nap/page_fetch.cpp +++ b/src/nap/page_fetch.cpp @@ -24,6 +24,7 @@ #include #include #include +#include namespace nap { namespace { @@ -35,6 +36,29 @@ namespace { return std::equal(protocol, protocol + protocolLen, parUrl.begin()); } + + std::tuple, std::string_view, std::string_view> make_raw_string ( + const std::ostringstream& head, + const std::ostringstream& body + ) { + //TODO: use .view() with c++20 + auto head_str = head.str(); + auto body_str = body.str(); + + const std::size_t size = head_str.size() + 1 + body_str.size(); + auto ret = std::make_unique(size); + + std::copy(head_str.begin(), head_str.end(), ret.get()); + ret[head_str.size()] = '\n'; + std::copy(body_str.begin(), body_str.end(), ret.get() + head_str.size() + 1); + + const char* const buff = ret.get(); + return std::make_tuple( + std::move(ret), + std::string_view(buff, head_str.size()), + std::string_view(buff + head_str.size() + 1, body_str.size()) + ); + } } //unnamed namespace HttpResponse page_fetch ( @@ -73,14 +97,16 @@ HttpResponse page_fetch ( HttpResponse resp; resp.code = easy.get_info().get(); - resp.raw = header_oss.str(); - resp.raw += "\n"; - const std::size_t body_start = resp.raw.size(); - resp.raw += body_oss.str(); - std::string_view raw_view(resp.raw); - resp.body = raw_view.substr(body_start); - auto parsed_header = header_parse(raw_view.substr(0, body_start)); + std::string_view head; + { + auto [raw, head_tmp, body] = make_raw_string(header_oss, body_oss); + head = head_tmp; + resp.raw = std::move(raw); + resp.body = body; + } + + auto parsed_header = header_parse(head); resp.header = std::move(parsed_header.fields); assert(resp.code == parsed_header.code); resp.http_ver = parsed_header.version;