123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- //
- // 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
|