/* Copyright 2017, Michele Santullo * This file is part of "tawashi". * * "tawashi" is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * "tawashi" is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with "tawashi". If not, see . */ #include "cgi_post.hpp" #include "cgi_env.hpp" #include "split_get_vars.hpp" #include "escapist.hpp" #include "sanitized_utf8.hpp" #include #include #include #include #include #include namespace tawashi { UnsupportedContentTypeException::UnsupportedContentTypeException (const boost::string_view& parMessage) : TawashiException(ErrorReasons::UnsupportedContentType, parMessage) { } namespace cgi { namespace { bool valid_content_type (const Env& parEnv) { if (parEnv.content_type_split().type != "application" or parEnv.content_type_split().subtype != "x-www-form-urlencoded") { return false; } return true; } std::string read_n (std::istream& parSrc, std::size_t parSize) { if (0 == parSize) return std::string(); std::string original_data; original_data.reserve(parSize); std::copy_n( std::istream_iterator(parSrc), parSize, std::back_inserter(original_data) ); return sanitized_utf8(original_data); } } //unnamed namespace const PostMapType& read_post (std::istream& parSrc, const Env& parEnv) { return read_post(parSrc, parEnv, parEnv.content_length()); } const PostMapType& read_post (std::istream& parSrc, const Env& parEnv, std::size_t parMaxLen) { static bool already_read = false; static PostMapType map; static std::string original_data; if (not already_read) { assert(original_data.empty()); assert(map.empty()); if (not valid_content_type(parEnv)) { throw UnsupportedContentTypeException(parEnv.content_type()); } const auto input_len = std::min(parMaxLen, parEnv.content_length()); original_data = read_n(parSrc, input_len); Escapist houdini; for (auto& itm : split_env_vars(original_data)) { std::string key(houdini.unescape_url(itm.first)); std::string val(houdini.unescape_url(itm.second)); map[std::move(key)] = std::move(val); } already_read = true; } return map; } } //namespace cgi } //namespace tawashi