123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- //
- // MultipartReader.cpp
- //
- // Library: Net
- // Package: Messages
- // Module: MultipartReader
- //
- // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
- // and Contributors.
- //
- // SPDX-License-Identifier: BSL-1.0
- //
- #include "Poco/Net/MultipartReader.h"
- #include "Poco/Net/MessageHeader.h"
- #include "Poco/Net/NetException.h"
- #include "Poco/Ascii.h"
- using Poco::BufferedStreamBuf;
- namespace Poco {
- namespace Net {
- //
- // MultipartStreamBuf
- //
- MultipartStreamBuf::MultipartStreamBuf(std::istream& istr, const std::string& boundary):
- BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::in),
- _istr(istr),
- _boundary(boundary),
- _lastPart(false)
- {
- poco_assert (!boundary.empty() && boundary.length() < STREAM_BUFFER_SIZE - 6);
- }
- MultipartStreamBuf::~MultipartStreamBuf()
- {
- }
- int MultipartStreamBuf::readFromDevice(char* buffer, std::streamsize length)
- {
- poco_assert_dbg (length >= _boundary.length() + 6);
- static const int eof = std::char_traits<char>::eof();
- std::streambuf& buf = *_istr.rdbuf();
- int n = 0;
- int ch = buf.sbumpc();
- if (ch == eof) return -1;
- *buffer++ = (char) ch; ++n;
- if (ch == '\n' || (ch == '\r' && buf.sgetc() == '\n'))
- {
- if (ch == '\r')
- {
- ch = buf.sbumpc(); // '\n'
- *buffer++ = (char) ch; ++n;
- }
- ch = buf.sgetc();
- if (ch == '\r' || ch == '\n') return n;
- *buffer++ = (char) buf.sbumpc(); ++n;
- if (ch == '-' && buf.sgetc() == '-')
- {
- ch = buf.sbumpc(); // '-'
- *buffer++ = (char) ch; ++n;
- std::string::const_iterator it = _boundary.begin();
- std::string::const_iterator end = _boundary.end();
- ch = buf.sbumpc();
- *buffer++ = (char) ch; ++n;
- while (it != end && ch == *it)
- {
- ++it;
- ch = buf.sbumpc();
- *buffer++ = (char) ch; ++n;
- }
- if (it == end)
- {
- if (ch == '\n' || (ch == '\r' && buf.sgetc() == '\n'))
- {
- if (ch == '\r')
- {
- buf.sbumpc(); // '\n'
- }
- return 0;
- }
- else if (ch == '-' && buf.sgetc() == '-')
- {
- buf.sbumpc(); // '-'
- _lastPart = true;
- return 0;
- }
- }
- }
- }
- ch = buf.sgetc();
- while (ch != eof && ch != '\r' && ch != '\n' && n < length)
- {
- *buffer++ = (char) buf.sbumpc(); ++n;
- ch = buf.sgetc();
- }
- return n;
- }
- bool MultipartStreamBuf::lastPart() const
- {
- return _lastPart;
- }
- //
- // MultipartIOS
- //
- MultipartIOS::MultipartIOS(std::istream& istr, const std::string& boundary):
- _buf(istr, boundary)
- {
- poco_ios_init(&_buf);
- }
- MultipartIOS::~MultipartIOS()
- {
- try
- {
- _buf.sync();
- }
- catch (...)
- {
- }
- }
- MultipartStreamBuf* MultipartIOS::rdbuf()
- {
- return &_buf;
- }
- bool MultipartIOS::lastPart() const
- {
- return _buf.lastPart();
- }
- //
- // MultipartInputStream
- //
- MultipartInputStream::MultipartInputStream(std::istream& istr, const std::string& boundary):
- MultipartIOS(istr, boundary),
- std::istream(&_buf)
- {
- }
- MultipartInputStream::~MultipartInputStream()
- {
- }
- //
- // MultipartReader
- //
- MultipartReader::MultipartReader(std::istream& istr):
- _istr(istr),
- _pMPI(0)
- {
- }
- MultipartReader::MultipartReader(std::istream& istr, const std::string& boundary):
- _istr(istr),
- _boundary(boundary),
- _pMPI(0)
- {
- }
- MultipartReader::~MultipartReader()
- {
- delete _pMPI;
- }
- void MultipartReader::nextPart(MessageHeader& messageHeader)
- {
- if (!_pMPI)
- {
- if (_boundary.empty())
- guessBoundary();
- else
- findFirstBoundary();
- }
- else if (_pMPI->lastPart())
- {
- throw MultipartException("No more parts available");
- }
- parseHeader(messageHeader);
- delete _pMPI;
- _pMPI = new MultipartInputStream(_istr, _boundary);
- }
- bool MultipartReader::hasNextPart()
- {
- return (!_pMPI || !_pMPI->lastPart()) && _istr.good();
- }
-
- std::istream& MultipartReader::stream() const
- {
- poco_check_ptr (_pMPI);
-
- return *_pMPI;
- }
- const std::string& MultipartReader::boundary() const
- {
- return _boundary;
- }
- void MultipartReader::findFirstBoundary()
- {
- std::string expect("--");
- expect.append(_boundary);
- std::string line;
- line.reserve(expect.length());
- bool ok = true;
- do
- {
- ok = readLine(line, expect.length());
- }
- while (ok && line != expect);
- if (!ok) throw MultipartException("No boundary line found");
- }
- void MultipartReader::guessBoundary()
- {
- static const int eof = std::char_traits<char>::eof();
- int ch = _istr.get();
- while (Poco::Ascii::isSpace(ch))
- ch = _istr.get();
- if (ch == '-' && _istr.peek() == '-')
- {
- _istr.get();
- ch = _istr.peek();
- while (ch != eof && ch != '\r' && ch != '\n' && _boundary.size() < 128) // Note: should be no longer than 70 chars acc. to RFC 2046
- {
- _boundary += (char) _istr.get();
- ch = _istr.peek();
- }
- if (ch != '\r' && ch != '\n')
- throw MultipartException("Invalid boundary line found");
- if (ch == '\r' || ch == '\n')
- _istr.get();
- if (_istr.peek() == '\n')
- _istr.get();
- }
- else throw MultipartException("No boundary line found");
- }
- void MultipartReader::parseHeader(MessageHeader& messageHeader)
- {
- messageHeader.clear();
- messageHeader.read(_istr);
- int ch = _istr.get();
- if (ch == '\r' && _istr.peek() == '\n') _istr.get();
- }
- bool MultipartReader::readLine(std::string& line, std::string::size_type n)
- {
- static const int eof = std::char_traits<char>::eof();
- static const int maxLength = 1024;
- line.clear();
- int ch = _istr.peek();
- int length = 0;
- while (ch != eof && ch != '\r' && ch != '\n' && length < maxLength)
- {
- ch = (char) _istr.get();
- if (line.length() < n)
- line += static_cast<char>(ch);
- ch = _istr.peek();
- length++;
- }
- if (ch != eof) _istr.get();
- if (ch == '\r' && _istr.peek() == '\n') _istr.get();
- return ch != eof && length < maxLength;
- }
- } } // namespace Poco::Net
|