MessageHeader.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. //
  2. // MessageHeader.cpp
  3. //
  4. // Library: Net
  5. // Package: Messages
  6. // Module: MessageHeader
  7. //
  8. // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
  9. // and Contributors.
  10. //
  11. // SPDX-License-Identifier: BSL-1.0
  12. //
  13. #include "Poco/Net/MessageHeader.h"
  14. #include "Poco/Net/NetException.h"
  15. #include "Poco/String.h"
  16. #include "Poco/Ascii.h"
  17. #include "Poco/TextConverter.h"
  18. #include "Poco/StringTokenizer.h"
  19. #include "Poco/Base64Decoder.h"
  20. #include "Poco/UTF8Encoding.h"
  21. #include <sstream>
  22. namespace Poco {
  23. namespace Net {
  24. MessageHeader::MessageHeader():
  25. _fieldLimit(DFL_FIELD_LIMIT)
  26. {
  27. }
  28. MessageHeader::MessageHeader(const MessageHeader& messageHeader):
  29. NameValueCollection(messageHeader),
  30. _fieldLimit(DFL_FIELD_LIMIT)
  31. {
  32. }
  33. MessageHeader::~MessageHeader()
  34. {
  35. }
  36. MessageHeader& MessageHeader::operator = (const MessageHeader& messageHeader)
  37. {
  38. NameValueCollection::operator = (messageHeader);
  39. return *this;
  40. }
  41. void MessageHeader::write(std::ostream& ostr) const
  42. {
  43. NameValueCollection::ConstIterator it = begin();
  44. while (it != end())
  45. {
  46. ostr << it->first << ": " << it->second << "\r\n";
  47. ++it;
  48. }
  49. }
  50. void MessageHeader::read(std::istream& istr)
  51. {
  52. static const int eof = std::char_traits<char>::eof();
  53. std::streambuf& buf = *istr.rdbuf();
  54. std::string name;
  55. std::string value;
  56. name.reserve(32);
  57. value.reserve(64);
  58. int ch = buf.sbumpc();
  59. int fields = 0;
  60. while (ch != eof && ch != '\r' && ch != '\n')
  61. {
  62. if (_fieldLimit > 0 && fields == _fieldLimit)
  63. throw MessageException("Too many header fields");
  64. name.clear();
  65. value.clear();
  66. while (ch != eof && ch != ':' && ch != '\n' && name.length() < MAX_NAME_LENGTH) { name += static_cast<char>(ch); ch = buf.sbumpc(); }
  67. if (ch == '\n') { ch = buf.sbumpc(); continue; } // ignore invalid header lines
  68. if (ch != ':') throw MessageException("Field name too long/no colon found");
  69. if (ch != eof) ch = buf.sbumpc(); // ':'
  70. while (ch != eof && Poco::Ascii::isSpace(ch) && ch != '\r' && ch != '\n') ch = buf.sbumpc();
  71. while (ch != eof && ch != '\r' && ch != '\n' && value.length() < MAX_VALUE_LENGTH) { value += static_cast<char>(ch); ch = buf.sbumpc(); }
  72. if (ch == '\r') ch = buf.sbumpc();
  73. if (ch == '\n')
  74. ch = buf.sbumpc();
  75. else if (ch != eof)
  76. throw MessageException("Field value too long/no CRLF found");
  77. while (ch == ' ' || ch == '\t') // folding
  78. {
  79. while (ch != eof && ch != '\r' && ch != '\n' && value.length() < MAX_VALUE_LENGTH) { value += static_cast<char>(ch); ch = buf.sbumpc(); }
  80. if (ch == '\r') ch = buf.sbumpc();
  81. if (ch == '\n')
  82. ch = buf.sbumpc();
  83. else if (ch != eof)
  84. throw MessageException("Folded field value too long/no CRLF found");
  85. }
  86. Poco::trimRightInPlace(value);
  87. add(name, decodeWord(value));
  88. ++fields;
  89. }
  90. istr.putback(static_cast<char>(ch));
  91. }
  92. int MessageHeader::getFieldLimit() const
  93. {
  94. return _fieldLimit;
  95. }
  96. void MessageHeader::setFieldLimit(int limit)
  97. {
  98. poco_assert (limit >= 0);
  99. _fieldLimit = limit;
  100. }
  101. bool MessageHeader::hasToken(const std::string& fieldName, const std::string& token) const
  102. {
  103. std::string field = get(fieldName, "");
  104. std::vector<std::string> tokens;
  105. splitElements(field, tokens, true);
  106. for (std::vector<std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
  107. {
  108. if (Poco::icompare(*it, token) == 0)
  109. return true;
  110. }
  111. return false;
  112. }
  113. void MessageHeader::splitElements(const std::string& s, std::vector<std::string>& elements, bool ignoreEmpty)
  114. {
  115. elements.clear();
  116. std::string::const_iterator it = s.begin();
  117. std::string::const_iterator end = s.end();
  118. std::string elem;
  119. elem.reserve(64);
  120. while (it != end)
  121. {
  122. if (*it == '"')
  123. {
  124. elem += *it++;
  125. while (it != end && *it != '"')
  126. {
  127. if (*it == '\\')
  128. {
  129. ++it;
  130. if (it != end) elem += *it++;
  131. }
  132. else elem += *it++;
  133. }
  134. if (it != end) elem += *it++;
  135. }
  136. else if (*it == '\\')
  137. {
  138. ++it;
  139. if (it != end) elem += *it++;
  140. }
  141. else if (*it == ',')
  142. {
  143. Poco::trimInPlace(elem);
  144. if (!ignoreEmpty || !elem.empty())
  145. elements.push_back(elem);
  146. elem.clear();
  147. ++it;
  148. }
  149. else elem += *it++;
  150. }
  151. if (!elem.empty())
  152. {
  153. Poco::trimInPlace(elem);
  154. if (!ignoreEmpty || !elem.empty())
  155. elements.push_back(elem);
  156. }
  157. }
  158. void MessageHeader::splitParameters(const std::string& s, std::string& value, NameValueCollection& parameters)
  159. {
  160. value.clear();
  161. parameters.clear();
  162. std::string::const_iterator it = s.begin();
  163. std::string::const_iterator end = s.end();
  164. while (it != end && Poco::Ascii::isSpace(*it)) ++it;
  165. while (it != end && *it != ';') value += *it++;
  166. Poco::trimRightInPlace(value);
  167. if (it != end) ++it;
  168. splitParameters(it, end, parameters);
  169. }
  170. void MessageHeader::splitParameters(const std::string::const_iterator& begin, const std::string::const_iterator& end, NameValueCollection& parameters)
  171. {
  172. std::string pname;
  173. std::string pvalue;
  174. pname.reserve(32);
  175. pvalue.reserve(64);
  176. std::string::const_iterator it = begin;
  177. while (it != end)
  178. {
  179. pname.clear();
  180. pvalue.clear();
  181. while (it != end && Poco::Ascii::isSpace(*it)) ++it;
  182. while (it != end && *it != '=' && *it != ';') pname += *it++;
  183. Poco::trimRightInPlace(pname);
  184. if (it != end && *it != ';') ++it;
  185. while (it != end && Poco::Ascii::isSpace(*it)) ++it;
  186. while (it != end && *it != ';')
  187. {
  188. if (*it == '"')
  189. {
  190. ++it;
  191. while (it != end && *it != '"')
  192. {
  193. if (*it == '\\')
  194. {
  195. ++it;
  196. if (it != end) pvalue += *it++;
  197. }
  198. else pvalue += *it++;
  199. }
  200. if (it != end) ++it;
  201. }
  202. else if (*it == '\\')
  203. {
  204. ++it;
  205. if (it != end) pvalue += *it++;
  206. }
  207. else pvalue += *it++;
  208. }
  209. Poco::trimRightInPlace(pvalue);
  210. if (!pname.empty()) parameters.add(pname, pvalue);
  211. if (it != end) ++it;
  212. }
  213. }
  214. void MessageHeader::quote(const std::string& value, std::string& result, bool allowSpace)
  215. {
  216. bool mustQuote = false;
  217. for (std::string::const_iterator it = value.begin(); !mustQuote && it != value.end(); ++it)
  218. {
  219. if (!Poco::Ascii::isAlphaNumeric(*it) && *it != '.' && *it != '_' && *it != '-' && !(Poco::Ascii::isSpace(*it) && allowSpace))
  220. mustQuote = true;
  221. }
  222. if (mustQuote) result += '"';
  223. result.append(value);
  224. if (mustQuote) result += '"';
  225. }
  226. void MessageHeader::decodeRFC2047(const std::string& ins, std::string& outs, const std::string& charset_to)
  227. {
  228. std::string tempout;
  229. StringTokenizer tokens(ins, "?");
  230. std::string charset = toUpper(tokens[0]);
  231. std::string encoding = toUpper(tokens[1]);
  232. std::string text = tokens[2];
  233. std::istringstream istr(text);
  234. if (encoding == "B")
  235. {
  236. // Base64 encoding.
  237. Base64Decoder decoder(istr);
  238. for (char c; decoder.get(c); tempout += c) {}
  239. }
  240. else if (encoding == "Q")
  241. {
  242. // Quoted encoding.
  243. for (char c; istr.get(c);)
  244. {
  245. if (c == '_')
  246. {
  247. //RFC 2047 _ is a space.
  248. tempout += " ";
  249. continue;
  250. }
  251. // FIXME: check that we have enought chars-
  252. if (c == '=')
  253. {
  254. // The next two chars are hex representation of the complete byte.
  255. std::string hex;
  256. for (int i = 0; i < 2; i++)
  257. {
  258. istr.get(c);
  259. hex += c;
  260. }
  261. hex = toUpper(hex);
  262. tempout += (char)(int)strtol(hex.c_str(), 0, 16);
  263. continue;
  264. }
  265. tempout += c;
  266. }
  267. }
  268. else
  269. {
  270. // Wrong encoding
  271. outs = ins;
  272. return;
  273. }
  274. // convert to the right charset.
  275. if (charset != charset_to)
  276. {
  277. try
  278. {
  279. TextEncoding& enc = TextEncoding::byName(charset);
  280. TextEncoding& dec = TextEncoding::byName(charset_to);
  281. TextConverter converter(enc, dec);
  282. converter.convert(tempout, outs);
  283. }
  284. catch (...)
  285. {
  286. // FIXME: Unsuported encoding...
  287. outs = tempout;
  288. }
  289. }
  290. else
  291. {
  292. // Not conversion necesary.
  293. outs = tempout;
  294. }
  295. }
  296. std::string MessageHeader::decodeWord(const std::string& text, const std::string& charset)
  297. {
  298. std::string outs, tmp = text;
  299. do {
  300. std::string tmp2;
  301. // find the begining of the next rfc2047 chunk
  302. size_t pos = tmp.find("=?");
  303. if (pos == std::string::npos) {
  304. // No more found, return
  305. outs += tmp;
  306. break;
  307. }
  308. // check if there are standar text before the rfc2047 chunk, and if so, copy it.
  309. if (pos > 0) {
  310. outs += tmp.substr(0, pos);
  311. }
  312. // remove text already copied.
  313. tmp = tmp.substr(pos + 2);
  314. // find the first separator
  315. size_t pos1 = tmp.find("?");
  316. if (pos1 == std::string::npos) {
  317. // not found.
  318. outs += tmp;
  319. break;
  320. }
  321. // find the second separator
  322. size_t pos2 = tmp.find("?", pos1 + 1);
  323. if (pos2 == std::string::npos) {
  324. // not found
  325. outs += tmp;
  326. break;
  327. }
  328. // find the end of the actual rfc2047 chunk
  329. size_t pos3 = tmp.find("?=", pos2 + 1);
  330. if (pos3 == std::string::npos) {
  331. // not found.
  332. outs += tmp;
  333. break;
  334. }
  335. // At this place, there are a valid rfc2047 chunk, so decode and copy the result.
  336. decodeRFC2047(tmp.substr(0, pos3), tmp2, charset);
  337. outs += tmp2;
  338. // Jump at the rest of the string and repeat the whole process.
  339. tmp = tmp.substr(pos3 + 2);
  340. } while (true);
  341. return outs;
  342. }
  343. } } // namespace Poco::Net