diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
commit | 2d37894b1b037cf24231090eda8589bbb44fb6fc (patch) | |
tree | be835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/poco/Net/src/MessageHeader.cpp | |
parent | 718c552901d703c502ccbefdfc3c9028d608b947 (diff) | |
download | ydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/poco/Net/src/MessageHeader.cpp')
-rw-r--r-- | contrib/libs/poco/Net/src/MessageHeader.cpp | 788 |
1 files changed, 394 insertions, 394 deletions
diff --git a/contrib/libs/poco/Net/src/MessageHeader.cpp b/contrib/libs/poco/Net/src/MessageHeader.cpp index d98531487b..a684b3cf5d 100644 --- a/contrib/libs/poco/Net/src/MessageHeader.cpp +++ b/contrib/libs/poco/Net/src/MessageHeader.cpp @@ -1,394 +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 +// +// 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 |