diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/poco/Net/src/MessageHeader.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/poco/Net/src/MessageHeader.cpp')
-rw-r--r-- | contrib/libs/poco/Net/src/MessageHeader.cpp | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/contrib/libs/poco/Net/src/MessageHeader.cpp b/contrib/libs/poco/Net/src/MessageHeader.cpp new file mode 100644 index 0000000000..a684b3cf5d --- /dev/null +++ b/contrib/libs/poco/Net/src/MessageHeader.cpp @@ -0,0 +1,394 @@ +// +// MessageHeader.cpp +// +// Library: Net +// Package: Messages +// Module: MessageHeader +// +// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/Net/MessageHeader.h" +#include "Poco/Net/NetException.h" +#include "Poco/String.h" +#include "Poco/Ascii.h" +#include "Poco/TextConverter.h" +#include "Poco/StringTokenizer.h" +#include "Poco/Base64Decoder.h" +#include "Poco/UTF8Encoding.h" +#include <sstream> + + +namespace Poco { +namespace Net { + + +MessageHeader::MessageHeader(): + _fieldLimit(DFL_FIELD_LIMIT) +{ +} + + +MessageHeader::MessageHeader(const MessageHeader& messageHeader): + NameValueCollection(messageHeader), + _fieldLimit(DFL_FIELD_LIMIT) +{ +} + + +MessageHeader::~MessageHeader() +{ +} + + +MessageHeader& MessageHeader::operator = (const MessageHeader& messageHeader) +{ + NameValueCollection::operator = (messageHeader); + return *this; +} + + +void MessageHeader::write(std::ostream& ostr) const +{ + NameValueCollection::ConstIterator it = begin(); + while (it != end()) + { + ostr << it->first << ": " << it->second << "\r\n"; + ++it; + } +} + + +void MessageHeader::read(std::istream& istr) +{ + static const int eof = std::char_traits<char>::eof(); + std::streambuf& buf = *istr.rdbuf(); + + std::string name; + std::string value; + name.reserve(32); + value.reserve(64); + int ch = buf.sbumpc(); + int fields = 0; + while (ch != eof && ch != '\r' && ch != '\n') + { + if (_fieldLimit > 0 && fields == _fieldLimit) + throw MessageException("Too many header fields"); + name.clear(); + value.clear(); + while (ch != eof && ch != ':' && ch != '\n' && name.length() < MAX_NAME_LENGTH) { name += static_cast<char>(ch); ch = buf.sbumpc(); } + if (ch == '\n') { ch = buf.sbumpc(); continue; } // ignore invalid header lines + if (ch != ':') throw MessageException("Field name too long/no colon found"); + if (ch != eof) ch = buf.sbumpc(); // ':' + while (ch != eof && Poco::Ascii::isSpace(ch) && ch != '\r' && ch != '\n') ch = buf.sbumpc(); + while (ch != eof && ch != '\r' && ch != '\n' && value.length() < MAX_VALUE_LENGTH) { value += static_cast<char>(ch); ch = buf.sbumpc(); } + if (ch == '\r') ch = buf.sbumpc(); + if (ch == '\n') + ch = buf.sbumpc(); + else if (ch != eof) + throw MessageException("Field value too long/no CRLF found"); + while (ch == ' ' || ch == '\t') // folding + { + while (ch != eof && ch != '\r' && ch != '\n' && value.length() < MAX_VALUE_LENGTH) { value += static_cast<char>(ch); ch = buf.sbumpc(); } + if (ch == '\r') ch = buf.sbumpc(); + if (ch == '\n') + ch = buf.sbumpc(); + else if (ch != eof) + throw MessageException("Folded field value too long/no CRLF found"); + } + Poco::trimRightInPlace(value); + add(name, decodeWord(value)); + ++fields; + } + istr.putback(static_cast<char>(ch)); +} + + +int MessageHeader::getFieldLimit() const +{ + return _fieldLimit; +} + + +void MessageHeader::setFieldLimit(int limit) +{ + poco_assert (limit >= 0); + + _fieldLimit = limit; +} + + +bool MessageHeader::hasToken(const std::string& fieldName, const std::string& token) const +{ + std::string field = get(fieldName, ""); + std::vector<std::string> tokens; + splitElements(field, tokens, true); + for (std::vector<std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) + { + if (Poco::icompare(*it, token) == 0) + return true; + } + return false; +} + + +void MessageHeader::splitElements(const std::string& s, std::vector<std::string>& elements, bool ignoreEmpty) +{ + elements.clear(); + std::string::const_iterator it = s.begin(); + std::string::const_iterator end = s.end(); + std::string elem; + elem.reserve(64); + while (it != end) + { + if (*it == '"') + { + elem += *it++; + while (it != end && *it != '"') + { + if (*it == '\\') + { + ++it; + if (it != end) elem += *it++; + } + else elem += *it++; + } + if (it != end) elem += *it++; + } + else if (*it == '\\') + { + ++it; + if (it != end) elem += *it++; + } + else if (*it == ',') + { + Poco::trimInPlace(elem); + if (!ignoreEmpty || !elem.empty()) + elements.push_back(elem); + elem.clear(); + ++it; + } + else elem += *it++; + } + if (!elem.empty()) + { + Poco::trimInPlace(elem); + if (!ignoreEmpty || !elem.empty()) + elements.push_back(elem); + } +} + + +void MessageHeader::splitParameters(const std::string& s, std::string& value, NameValueCollection& parameters) +{ + value.clear(); + parameters.clear(); + std::string::const_iterator it = s.begin(); + std::string::const_iterator end = s.end(); + while (it != end && Poco::Ascii::isSpace(*it)) ++it; + while (it != end && *it != ';') value += *it++; + Poco::trimRightInPlace(value); + if (it != end) ++it; + splitParameters(it, end, parameters); +} + + +void MessageHeader::splitParameters(const std::string::const_iterator& begin, const std::string::const_iterator& end, NameValueCollection& parameters) +{ + std::string pname; + std::string pvalue; + pname.reserve(32); + pvalue.reserve(64); + std::string::const_iterator it = begin; + while (it != end) + { + pname.clear(); + pvalue.clear(); + while (it != end && Poco::Ascii::isSpace(*it)) ++it; + while (it != end && *it != '=' && *it != ';') pname += *it++; + Poco::trimRightInPlace(pname); + if (it != end && *it != ';') ++it; + while (it != end && Poco::Ascii::isSpace(*it)) ++it; + while (it != end && *it != ';') + { + if (*it == '"') + { + ++it; + while (it != end && *it != '"') + { + if (*it == '\\') + { + ++it; + if (it != end) pvalue += *it++; + } + else pvalue += *it++; + } + if (it != end) ++it; + } + else if (*it == '\\') + { + ++it; + if (it != end) pvalue += *it++; + } + else pvalue += *it++; + } + Poco::trimRightInPlace(pvalue); + if (!pname.empty()) parameters.add(pname, pvalue); + if (it != end) ++it; + } +} + + +void MessageHeader::quote(const std::string& value, std::string& result, bool allowSpace) +{ + bool mustQuote = false; + for (std::string::const_iterator it = value.begin(); !mustQuote && it != value.end(); ++it) + { + if (!Poco::Ascii::isAlphaNumeric(*it) && *it != '.' && *it != '_' && *it != '-' && !(Poco::Ascii::isSpace(*it) && allowSpace)) + mustQuote = true; + } + if (mustQuote) result += '"'; + result.append(value); + if (mustQuote) result += '"'; +} + + +void MessageHeader::decodeRFC2047(const std::string& ins, std::string& outs, const std::string& charset_to) +{ + std::string tempout; + StringTokenizer tokens(ins, "?"); + + std::string charset = toUpper(tokens[0]); + std::string encoding = toUpper(tokens[1]); + std::string text = tokens[2]; + + std::istringstream istr(text); + + if (encoding == "B") + { + // Base64 encoding. + Base64Decoder decoder(istr); + for (char c; decoder.get(c); tempout += c) {} + } + else if (encoding == "Q") + { + // Quoted encoding. + for (char c; istr.get(c);) + { + if (c == '_') + { + //RFC 2047 _ is a space. + tempout += " "; + continue; + } + + // FIXME: check that we have enought chars- + if (c == '=') + { + // The next two chars are hex representation of the complete byte. + std::string hex; + for (int i = 0; i < 2; i++) + { + istr.get(c); + hex += c; + } + hex = toUpper(hex); + tempout += (char)(int)strtol(hex.c_str(), 0, 16); + continue; + } + tempout += c; + } + } + else + { + // Wrong encoding + outs = ins; + return; + } + + // convert to the right charset. + if (charset != charset_to) + { + try + { + TextEncoding& enc = TextEncoding::byName(charset); + TextEncoding& dec = TextEncoding::byName(charset_to); + TextConverter converter(enc, dec); + converter.convert(tempout, outs); + } + catch (...) + { + // FIXME: Unsuported encoding... + outs = tempout; + } + } + else + { + // Not conversion necesary. + outs = tempout; + } +} + + +std::string MessageHeader::decodeWord(const std::string& text, const std::string& charset) +{ + std::string outs, tmp = text; + do { + std::string tmp2; + // find the begining of the next rfc2047 chunk + size_t pos = tmp.find("=?"); + if (pos == std::string::npos) { + // No more found, return + outs += tmp; + break; + } + + // check if there are standar text before the rfc2047 chunk, and if so, copy it. + if (pos > 0) { + outs += tmp.substr(0, pos); + } + + // remove text already copied. + tmp = tmp.substr(pos + 2); + + // find the first separator + size_t pos1 = tmp.find("?"); + if (pos1 == std::string::npos) { + // not found. + outs += tmp; + break; + } + + // find the second separator + size_t pos2 = tmp.find("?", pos1 + 1); + if (pos2 == std::string::npos) { + // not found + outs += tmp; + break; + } + + // find the end of the actual rfc2047 chunk + size_t pos3 = tmp.find("?=", pos2 + 1); + if (pos3 == std::string::npos) { + // not found. + outs += tmp; + break; + + } + // At this place, there are a valid rfc2047 chunk, so decode and copy the result. + decodeRFC2047(tmp.substr(0, pos3), tmp2, charset); + outs += tmp2; + + // Jump at the rest of the string and repeat the whole process. + tmp = tmp.substr(pos3 + 2); + } while (true); + + return outs; +} + + +} } // namespace Poco::Net |