aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/poco/Net/src/MessageHeader.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/poco/Net/src/MessageHeader.cpp
downloadydb-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.cpp394
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