MultipartReader.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. //
  2. // MultipartReader.cpp
  3. //
  4. // Library: Net
  5. // Package: Messages
  6. // Module: MultipartReader
  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/MultipartReader.h"
  14. #include "Poco/Net/MessageHeader.h"
  15. #include "Poco/Net/NetException.h"
  16. #include "Poco/Ascii.h"
  17. using Poco::BufferedStreamBuf;
  18. namespace Poco {
  19. namespace Net {
  20. //
  21. // MultipartStreamBuf
  22. //
  23. MultipartStreamBuf::MultipartStreamBuf(std::istream& istr, const std::string& boundary):
  24. BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::in),
  25. _istr(istr),
  26. _boundary(boundary),
  27. _lastPart(false)
  28. {
  29. poco_assert (!boundary.empty() && boundary.length() < STREAM_BUFFER_SIZE - 6);
  30. }
  31. MultipartStreamBuf::~MultipartStreamBuf()
  32. {
  33. }
  34. int MultipartStreamBuf::readFromDevice(char* buffer, std::streamsize length)
  35. {
  36. poco_assert_dbg (length >= _boundary.length() + 6);
  37. static const int eof = std::char_traits<char>::eof();
  38. std::streambuf& buf = *_istr.rdbuf();
  39. int n = 0;
  40. int ch = buf.sbumpc();
  41. if (ch == eof) return -1;
  42. *buffer++ = (char) ch; ++n;
  43. if (ch == '\n' || (ch == '\r' && buf.sgetc() == '\n'))
  44. {
  45. if (ch == '\r')
  46. {
  47. ch = buf.sbumpc(); // '\n'
  48. *buffer++ = (char) ch; ++n;
  49. }
  50. ch = buf.sgetc();
  51. if (ch == '\r' || ch == '\n') return n;
  52. *buffer++ = (char) buf.sbumpc(); ++n;
  53. if (ch == '-' && buf.sgetc() == '-')
  54. {
  55. ch = buf.sbumpc(); // '-'
  56. *buffer++ = (char) ch; ++n;
  57. std::string::const_iterator it = _boundary.begin();
  58. std::string::const_iterator end = _boundary.end();
  59. ch = buf.sbumpc();
  60. *buffer++ = (char) ch; ++n;
  61. while (it != end && ch == *it)
  62. {
  63. ++it;
  64. ch = buf.sbumpc();
  65. *buffer++ = (char) ch; ++n;
  66. }
  67. if (it == end)
  68. {
  69. if (ch == '\n' || (ch == '\r' && buf.sgetc() == '\n'))
  70. {
  71. if (ch == '\r')
  72. {
  73. buf.sbumpc(); // '\n'
  74. }
  75. return 0;
  76. }
  77. else if (ch == '-' && buf.sgetc() == '-')
  78. {
  79. buf.sbumpc(); // '-'
  80. _lastPart = true;
  81. return 0;
  82. }
  83. }
  84. }
  85. }
  86. ch = buf.sgetc();
  87. while (ch != eof && ch != '\r' && ch != '\n' && n < length)
  88. {
  89. *buffer++ = (char) buf.sbumpc(); ++n;
  90. ch = buf.sgetc();
  91. }
  92. return n;
  93. }
  94. bool MultipartStreamBuf::lastPart() const
  95. {
  96. return _lastPart;
  97. }
  98. //
  99. // MultipartIOS
  100. //
  101. MultipartIOS::MultipartIOS(std::istream& istr, const std::string& boundary):
  102. _buf(istr, boundary)
  103. {
  104. poco_ios_init(&_buf);
  105. }
  106. MultipartIOS::~MultipartIOS()
  107. {
  108. try
  109. {
  110. _buf.sync();
  111. }
  112. catch (...)
  113. {
  114. }
  115. }
  116. MultipartStreamBuf* MultipartIOS::rdbuf()
  117. {
  118. return &_buf;
  119. }
  120. bool MultipartIOS::lastPart() const
  121. {
  122. return _buf.lastPart();
  123. }
  124. //
  125. // MultipartInputStream
  126. //
  127. MultipartInputStream::MultipartInputStream(std::istream& istr, const std::string& boundary):
  128. MultipartIOS(istr, boundary),
  129. std::istream(&_buf)
  130. {
  131. }
  132. MultipartInputStream::~MultipartInputStream()
  133. {
  134. }
  135. //
  136. // MultipartReader
  137. //
  138. MultipartReader::MultipartReader(std::istream& istr):
  139. _istr(istr),
  140. _pMPI(0)
  141. {
  142. }
  143. MultipartReader::MultipartReader(std::istream& istr, const std::string& boundary):
  144. _istr(istr),
  145. _boundary(boundary),
  146. _pMPI(0)
  147. {
  148. }
  149. MultipartReader::~MultipartReader()
  150. {
  151. delete _pMPI;
  152. }
  153. void MultipartReader::nextPart(MessageHeader& messageHeader)
  154. {
  155. if (!_pMPI)
  156. {
  157. if (_boundary.empty())
  158. guessBoundary();
  159. else
  160. findFirstBoundary();
  161. }
  162. else if (_pMPI->lastPart())
  163. {
  164. throw MultipartException("No more parts available");
  165. }
  166. parseHeader(messageHeader);
  167. delete _pMPI;
  168. _pMPI = new MultipartInputStream(_istr, _boundary);
  169. }
  170. bool MultipartReader::hasNextPart()
  171. {
  172. return (!_pMPI || !_pMPI->lastPart()) && _istr.good();
  173. }
  174. std::istream& MultipartReader::stream() const
  175. {
  176. poco_check_ptr (_pMPI);
  177. return *_pMPI;
  178. }
  179. const std::string& MultipartReader::boundary() const
  180. {
  181. return _boundary;
  182. }
  183. void MultipartReader::findFirstBoundary()
  184. {
  185. std::string expect("--");
  186. expect.append(_boundary);
  187. std::string line;
  188. line.reserve(expect.length());
  189. bool ok = true;
  190. do
  191. {
  192. ok = readLine(line, expect.length());
  193. }
  194. while (ok && line != expect);
  195. if (!ok) throw MultipartException("No boundary line found");
  196. }
  197. void MultipartReader::guessBoundary()
  198. {
  199. static const int eof = std::char_traits<char>::eof();
  200. int ch = _istr.get();
  201. while (Poco::Ascii::isSpace(ch))
  202. ch = _istr.get();
  203. if (ch == '-' && _istr.peek() == '-')
  204. {
  205. _istr.get();
  206. ch = _istr.peek();
  207. while (ch != eof && ch != '\r' && ch != '\n' && _boundary.size() < 128) // Note: should be no longer than 70 chars acc. to RFC 2046
  208. {
  209. _boundary += (char) _istr.get();
  210. ch = _istr.peek();
  211. }
  212. if (ch != '\r' && ch != '\n')
  213. throw MultipartException("Invalid boundary line found");
  214. if (ch == '\r' || ch == '\n')
  215. _istr.get();
  216. if (_istr.peek() == '\n')
  217. _istr.get();
  218. }
  219. else throw MultipartException("No boundary line found");
  220. }
  221. void MultipartReader::parseHeader(MessageHeader& messageHeader)
  222. {
  223. messageHeader.clear();
  224. messageHeader.read(_istr);
  225. int ch = _istr.get();
  226. if (ch == '\r' && _istr.peek() == '\n') _istr.get();
  227. }
  228. bool MultipartReader::readLine(std::string& line, std::string::size_type n)
  229. {
  230. static const int eof = std::char_traits<char>::eof();
  231. static const int maxLength = 1024;
  232. line.clear();
  233. int ch = _istr.peek();
  234. int length = 0;
  235. while (ch != eof && ch != '\r' && ch != '\n' && length < maxLength)
  236. {
  237. ch = (char) _istr.get();
  238. if (line.length() < n)
  239. line += static_cast<char>(ch);
  240. ch = _istr.peek();
  241. length++;
  242. }
  243. if (ch != eof) _istr.get();
  244. if (ch == '\r' && _istr.peek() == '\n') _istr.get();
  245. return ch != eof && length < maxLength;
  246. }
  247. } } // namespace Poco::Net