Throw when content-type is not application/json
This commit is contained in:
parent
6bafd923f3
commit
2c8e557bb4
5 changed files with 84 additions and 27 deletions
|
@ -18,6 +18,7 @@
|
||||||
#include "private/api_nap.hpp"
|
#include "private/api_nap.hpp"
|
||||||
#include "private/v1_endpoints.hpp"
|
#include "private/v1_endpoints.hpp"
|
||||||
#include "private/dateconv.hpp"
|
#include "private/dateconv.hpp"
|
||||||
|
#include "private/mime_split.hpp"
|
||||||
#include "duckhandy/int_conv.hpp"
|
#include "duckhandy/int_conv.hpp"
|
||||||
#include "api_nap_exception.hpp"
|
#include "api_nap_exception.hpp"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -98,6 +99,14 @@ void fill_creator_list (const sjd::element& elem, std::vector<Creator>& out) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string_view header_entry (const nap::HttpResponse& resp, std::string_view name) {
|
||||||
|
for (const auto& head : resp.header_list) {
|
||||||
|
if (equal(head.first, name))
|
||||||
|
return head.second;
|
||||||
|
}
|
||||||
|
return {""};
|
||||||
|
}
|
||||||
|
|
||||||
} //unnamed namespace
|
} //unnamed namespace
|
||||||
|
|
||||||
ApiNap::ApiNap (
|
ApiNap::ApiNap (
|
||||||
|
@ -265,6 +274,14 @@ ApiOutput<T> ApiNap::fetch_and_parse (const char* endpoint, F&& data_fill, bool
|
||||||
if (200 != resp.code)
|
if (200 != resp.code)
|
||||||
throw ServerError(resp);
|
throw ServerError(resp);
|
||||||
|
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
int parsed_char;
|
||||||
|
auto mime = tawashi::string_to_mime(header_entry(resp, "content-type"), ok, parsed_char);
|
||||||
|
if (ok and (not equal(mime.type, "application") or not equal(mime.subtype, "json")))
|
||||||
|
throw ContentTypeError(mime.type, mime.subtype);
|
||||||
|
}
|
||||||
|
|
||||||
T dataret;
|
T dataret;
|
||||||
{
|
{
|
||||||
std::unique_lock lock(m_json_mutex);
|
std::unique_lock lock(m_json_mutex);
|
||||||
|
|
|
@ -18,8 +18,21 @@
|
||||||
#include "api_nap_exception.hpp"
|
#include "api_nap_exception.hpp"
|
||||||
#include "nap/http_response.hpp"
|
#include "nap/http_response.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace oro {
|
namespace oro {
|
||||||
|
namespace {
|
||||||
|
std::size_t append_to_char_arary (std::string_view in, char* out, std::size_t offs, std::size_t capacity) {
|
||||||
|
assert(capacity >= offs + 1);
|
||||||
|
|
||||||
|
const std::size_t out_size = std::min(in.size(), capacity - offs - 1);
|
||||||
|
std::copy(in.begin(), in.begin() + out_size, out + offs);
|
||||||
|
out[out_size] = '\0';
|
||||||
|
|
||||||
|
return offs + out_size;
|
||||||
|
}
|
||||||
|
} //unnamed namespace
|
||||||
|
|
||||||
ServerError::ServerError (const nap::HttpResponse& resp) :
|
ServerError::ServerError (const nap::HttpResponse& resp) :
|
||||||
std::runtime_error(
|
std::runtime_error(
|
||||||
|
@ -35,4 +48,20 @@ int ServerError::error_code() const noexcept {
|
||||||
return m_err_code;
|
return m_err_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContentTypeError::ContentTypeError (std::string_view type, std::string_view subtype) :
|
||||||
|
std::runtime_error(
|
||||||
|
std::string("Unexpected content-type received: \"") +
|
||||||
|
std::string(type) + "/" + std::string(subtype) + "\""
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::size_t offs = 0;
|
||||||
|
offs = append_to_char_arary(type, m_content_type.data(), offs, m_content_type.size());
|
||||||
|
offs = append_to_char_arary("/", m_content_type.data(), offs, m_content_type.size());
|
||||||
|
offs = append_to_char_arary(subtype, m_content_type.data(), offs, m_content_type.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view ContentTypeError::content_type() const noexcept {
|
||||||
|
return {m_content_type.data()};
|
||||||
|
}
|
||||||
|
|
||||||
} //namespace oro
|
} //namespace oro
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <array>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace nap {
|
namespace nap {
|
||||||
struct HttpResponse;
|
struct HttpResponse;
|
||||||
|
@ -34,4 +36,13 @@ private:
|
||||||
int m_err_code;
|
int m_err_code;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ContentTypeError : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
explicit ContentTypeError (std::string_view type, std::string_view subtype);
|
||||||
|
std::string_view content_type() const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<char, 32> m_content_type;
|
||||||
|
};
|
||||||
|
|
||||||
} //namespace oro
|
} //namespace oro
|
||||||
|
|
|
@ -81,8 +81,8 @@
|
||||||
|
|
||||||
BOOST_FUSION_ADAPT_STRUCT(
|
BOOST_FUSION_ADAPT_STRUCT(
|
||||||
tawashi::SplitMime,
|
tawashi::SplitMime,
|
||||||
(boost::string_view, type)
|
(std::string_view, type)
|
||||||
(boost::string_view, subtype)
|
(std::string_view, subtype)
|
||||||
(tawashi::MimeParametersMapType, parameters)
|
(tawashi::MimeParametersMapType, parameters)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -90,26 +90,26 @@ namespace tawashi {
|
||||||
namespace {
|
namespace {
|
||||||
template <typename Iterator, typename Skipper>
|
template <typename Iterator, typename Skipper>
|
||||||
struct MimeGrammar : boost::spirit::qi::grammar<Iterator, tawashi::SplitMime(), Skipper> {
|
struct MimeGrammar : boost::spirit::qi::grammar<Iterator, tawashi::SplitMime(), Skipper> {
|
||||||
explicit MimeGrammar (const std::string* parString);
|
explicit MimeGrammar (std::string_view parString);
|
||||||
|
|
||||||
boost::spirit::qi::rule<Iterator, SplitMime(), Skipper> content_type;
|
boost::spirit::qi::rule<Iterator, SplitMime(), Skipper> content_type;
|
||||||
boost::spirit::qi::rule<Iterator, SplitMime(), Skipper> media_type;
|
boost::spirit::qi::rule<Iterator, SplitMime(), Skipper> media_type;
|
||||||
boost::spirit::qi::rule<Iterator, boost::string_view(), Skipper> type;
|
boost::spirit::qi::rule<Iterator, std::string_view(), Skipper> type;
|
||||||
boost::spirit::qi::rule<Iterator, boost::string_view(), Skipper> subtype;
|
boost::spirit::qi::rule<Iterator, std::string_view(), Skipper> subtype;
|
||||||
boost::spirit::qi::rule<Iterator, MimeParametersMapType::value_type(), Skipper> parameter;
|
boost::spirit::qi::rule<Iterator, MimeParametersMapType::value_type(), Skipper> parameter;
|
||||||
boost::spirit::qi::rule<Iterator, boost::string_view(), Skipper> attribute;
|
boost::spirit::qi::rule<Iterator, std::string_view(), Skipper> attribute;
|
||||||
boost::spirit::qi::rule<Iterator, boost::string_view(), Skipper> value;
|
boost::spirit::qi::rule<Iterator, std::string_view(), Skipper> value;
|
||||||
boost::spirit::qi::rule<Iterator, boost::string_view(), Skipper> quoted_string;
|
boost::spirit::qi::rule<Iterator, std::string_view(), Skipper> quoted_string;
|
||||||
boost::spirit::qi::rule<Iterator, boost::string_view(), Skipper> token;
|
boost::spirit::qi::rule<Iterator, std::string_view(), Skipper> token;
|
||||||
const std::string* m_master_string;
|
std::string_view m_master_string;
|
||||||
Iterator m_begin;
|
Iterator m_begin;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Iterator, typename Skipper>
|
template <typename Iterator, typename Skipper>
|
||||||
MimeGrammar<Iterator, Skipper>::MimeGrammar (const std::string* parString) :
|
MimeGrammar<Iterator, Skipper>::MimeGrammar (std::string_view parString) :
|
||||||
MimeGrammar::base_type(content_type),
|
MimeGrammar::base_type(content_type),
|
||||||
m_master_string(parString),
|
m_master_string(parString),
|
||||||
m_begin(m_master_string->cbegin())
|
m_begin(m_master_string.cbegin())
|
||||||
{
|
{
|
||||||
namespace px = boost::phoenix;
|
namespace px = boost::phoenix;
|
||||||
using boost::spirit::ascii::space;
|
using boost::spirit::ascii::space;
|
||||||
|
@ -119,7 +119,7 @@ namespace tawashi {
|
||||||
using boost::spirit::qi::raw;
|
using boost::spirit::qi::raw;
|
||||||
using boost::spirit::qi::_val;
|
using boost::spirit::qi::_val;
|
||||||
using boost::spirit::qi::lexeme;
|
using boost::spirit::qi::lexeme;
|
||||||
using boost::string_view;
|
using std::string_view;
|
||||||
using boost::spirit::_1;
|
using boost::spirit::_1;
|
||||||
|
|
||||||
content_type = -media_type;
|
content_type = -media_type;
|
||||||
|
@ -132,7 +132,7 @@ namespace tawashi {
|
||||||
|
|
||||||
token = raw[+(alnum | char_("_.-"))][
|
token = raw[+(alnum | char_("_.-"))][
|
||||||
_val = px::bind(
|
_val = px::bind(
|
||||||
&string_view::substr, px::construct<string_view>(px::ref(*m_master_string)),
|
&string_view::substr, px::construct<string_view>(px::ref(m_master_string)),
|
||||||
px::begin(_1) - px::ref(m_begin),
|
px::begin(_1) - px::ref(m_begin),
|
||||||
px::size(_1)
|
px::size(_1)
|
||||||
)
|
)
|
||||||
|
@ -144,7 +144,7 @@ namespace tawashi {
|
||||||
'"'
|
'"'
|
||||||
]
|
]
|
||||||
][_val = px::bind(
|
][_val = px::bind(
|
||||||
&string_view::substr, px::construct<string_view>(px::ref(*m_master_string)),
|
&string_view::substr, px::construct<string_view>(px::ref(m_master_string)),
|
||||||
px::begin(_1) + 1 - px::ref(m_begin),
|
px::begin(_1) + 1 - px::ref(m_begin),
|
||||||
px::size(_1) - 2
|
px::size(_1) - 2
|
||||||
)];
|
)];
|
||||||
|
@ -161,34 +161,34 @@ namespace tawashi {
|
||||||
};
|
};
|
||||||
} //unnamed namespace
|
} //unnamed namespace
|
||||||
|
|
||||||
SplitMime string_to_mime (const std::string* parMime, bool& parParseOk, int& parParsedCharCount) {
|
SplitMime string_to_mime (std::string_view parMime, bool& parParseOk, int& parParsedCharCount) {
|
||||||
using boost::spirit::qi::blank;
|
using boost::spirit::qi::blank;
|
||||||
using boost::spirit::qi::blank_type;
|
using boost::spirit::qi::blank_type;
|
||||||
|
|
||||||
MimeGrammar<std::string::const_iterator, blank_type> gramm(parMime);
|
MimeGrammar<std::string_view::const_iterator, blank_type> gramm(parMime);
|
||||||
SplitMime result;
|
SplitMime result;
|
||||||
|
|
||||||
parParseOk = false;
|
parParseOk = false;
|
||||||
parParsedCharCount = 0;
|
parParsedCharCount = 0;
|
||||||
|
|
||||||
std::string::const_iterator start_it = parMime->cbegin();
|
std::string_view::const_iterator start_it = parMime.cbegin();
|
||||||
const bool parse_ok = boost::spirit::qi::phrase_parse(
|
const bool parse_ok = boost::spirit::qi::phrase_parse(
|
||||||
start_it,
|
start_it,
|
||||||
parMime->cend(),
|
parMime.cend(),
|
||||||
gramm,
|
gramm,
|
||||||
blank,
|
blank,
|
||||||
result
|
result
|
||||||
);
|
);
|
||||||
|
|
||||||
parParseOk = parse_ok and (parMime->cend() == start_it);
|
parParseOk = parse_ok and (parMime.cend() == start_it);
|
||||||
parParsedCharCount = std::distance(parMime->cbegin(), start_it);
|
parParsedCharCount = std::distance(parMime.cbegin(), start_it);
|
||||||
assert(parParsedCharCount >= 0);
|
assert(parParsedCharCount >= 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string mime_to_string (const SplitMime& parMime, bool& parWriteOk) {
|
std::string mime_to_string (const SplitMime& parMime, bool& parWriteOk) {
|
||||||
namespace px = boost::phoenix;
|
namespace px = boost::phoenix;
|
||||||
using boost::string_view;
|
using std::string_view;
|
||||||
using boost::spirit::karma::generate;
|
using boost::spirit::karma::generate;
|
||||||
using boost::spirit::karma::char_;
|
using boost::spirit::karma::char_;
|
||||||
using boost::spirit::karma::string;
|
using boost::spirit::karma::string;
|
||||||
|
|
|
@ -17,19 +17,19 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <boost/utility/string_view.hpp>
|
|
||||||
#include <boost/container/flat_map.hpp>
|
#include <boost/container/flat_map.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace tawashi {
|
namespace tawashi {
|
||||||
typedef boost::container::flat_map<boost::string_view, boost::string_view> MimeParametersMapType;
|
typedef boost::container::flat_map<std::string_view, std::string_view> MimeParametersMapType;
|
||||||
|
|
||||||
struct SplitMime {
|
struct SplitMime {
|
||||||
boost::string_view type;
|
std::string_view type;
|
||||||
boost::string_view subtype;
|
std::string_view subtype;
|
||||||
MimeParametersMapType parameters;
|
MimeParametersMapType parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
SplitMime string_to_mime (const std::string* parMime, bool& parParseOk, int& parParsedCharCount);
|
SplitMime string_to_mime (std::string_view parMime, bool& parParseOk, int& parParsedCharCount);
|
||||||
std::string mime_to_string (const SplitMime& parMime, bool& parWriteOk);
|
std::string mime_to_string (const SplitMime& parMime, bool& parWriteOk);
|
||||||
} //namespace tawashi
|
} //namespace tawashi
|
||||||
|
|
Loading…
Reference in a new issue