--Boundary-00=_WPFT+Wxaa7HhZsh Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hello, Okay. Here is the class. It is only a rough draft and meant to get ideas on how to improve it. It is going to require the end applications provide a pointer to a QIODevice. Regards, Dawit A. --Boundary-00=_WPFT+Wxaa7HhZsh Content-Type: text/x-c++src; charset="iso-8859-1"; name="postjob.cpp" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="postjob.cpp" #define KIO_DEFAULT_BLOCK_SIZE 1024*256 PostJob::PostJob (const KURL& url, int command, const QByteArray& packedArgs, QIODevice * source, bool showProgressInfo) :TransferJob (url, command, packedArgs, QByteArray(), showProgressInfo), _bytesSent(0), _blockSize (KIO_DEFAULT_BLOCK_SIZE), _autoDeleteSource (false), _dataSource(source) { } PostJob::PostJob (const KURL& url, int command, const QByteArray& packedArgs, const QByteArray& data, bool showProgressInfo) :TransferJob (url, command, packedArgs, QByteArray(), showProgressInfo), _bytesSent(0), _blockSize (KIO_DEFAULT_BLOCK_SIZE), _autoDeleteSource (true) { // If the data is larger than the default block size use a temp file // to save the data and send it in segments to the io-slave. Otherwise, // simply use a QBuffer to store and transmit the data... if (data.size() < KIO_DEFAULT_BLOCK_SIZE) { _dataSource = new QBuffer (data); } else { KTempFile temp (QString::null, QString::null, 0600); temp.close (); _tempfile = temp.name (); _dataSource = new QFile (_tempfile); if (_dataSource->open (IO_WriteOnly)) { KIO::filesize_t offset = 0; KIO::filesize_t segment; while (offset < data.size()) { segment = (data.size () < _blockSize) ? data.size ():_blockSize; _dataSource->writeBlock (data.data() + offset, segment); offset += segment; } // Close it to force a flush. It will be re-opened when // start is invoked... _dataSource->close(); } } } PostJob::~PostJob () { if (_autoDeleteSource && _dataSource) { kdDebug(7007) << "PostJob dtor: Deleting pointer to data source" << endl; _dataSource->close (); delete _dataSource; _dataSource = 0; } // Unlink the tempfile if it exists. if (!_tempfile.isEmpty()) QFile::remove (_tempfile); } bool PostJob::isPortSafe() { bool valid = true; // filter out non https? protocols if ((m_url.protocol() != "http") && (m_url.protocol() != "https" )) valid = false; // filter out some malicious ports static const int bad_ports[] = { 1, // tcpmux 7, // echo 9, // discard 11, // systat 13, // daytime 15, // netstat 17, // qotd 19, // chargen 20, // ftp-data 21, // ftp-cntl 22, // ssh 23, // telnet 25, // smtp 37, // time 42, // name 43, // nicname 53, // domain 77, // priv-rjs 79, // finger 87, // ttylink 95, // supdup 101, // hostriame 102, // iso-tsap 103, // gppitnp 104, // acr-nema 109, // pop2 110, // pop3 111, // sunrpc 113, // auth 115, // sftp 117, // uucp-path 119, // nntp 123, // NTP 135, // loc-srv / epmap 139, // netbios 143, // imap2 179, // BGP 389, // ldap 512, // print / exec 513, // login 514, // shell 515, // printer 526, // tempo 530, // courier 531, // Chat 532, // netnews 540, // uucp 556, // remotefs 587, // sendmail 601, // 989, // ftps data 990, // ftps 992, // telnets 993, // imap/SSL 995, // pop3/SSL 1080, // SOCKS 2049, // nfs 4045, // lockd 6000, // x11 6667, // irc 0 }; for (int cnt=0; bad_ports[cnt]; ++cnt) { if (m_url.port() == bad_ports[cnt]) { valid = false; break; } } if( !valid ) { static bool override_loaded = false; static QValueList< int >* overriden_ports = NULL; if( !override_loaded ) { KConfig cfg( "kio_httprc", true ); overriden_ports = new QValueList< int >; *overriden_ports = cfg.readIntListEntry( "OverriddenPorts" ); override_loaded = true; } for (QValueList< int >::ConstIterator it = overriden_ports->begin(); it != overriden_ports->end(); ++it) { if( overriden_ports->contains(m_url.port())) valid = true; } } // if request is not valid, return an invalid transfer job if (!valid) { m_error = KIO::ERR_POST_DENIED; m_errorText = m_url.url(); } return valid; } void PostJob::setBlockSize (KIO::filesize_t size) { _blockSize = size; } KIO::filesize_t PostJob::blockSize () const { return _blockSize; } void PostJob::start (Slave* slave) { assert (_dataSource); if (_validatePort && !isPortSafe()) { slotFinished (); return; } // Open the source device if it is currently not opened. if (!_dataSource->isOpen() && !_dataSource->open (IO_ReadOnly)) { kdDebug (7007) << "PostJob::slotDataReq: Unable to open the post data source!!" << endl; m_error = KIO::ERR_INTERNAL; m_errorText = m_url.url(); slotFinished(); return; } m_totalSize = _dataSource->size(); if (m_totalSize == 0) { kdDebug (7007) << "PostJob::slotDataReq: Hmmm... the post data source is empty!!" << endl; m_error = KIO::ERR_INTERNAL; m_errorText = m_url.url(); slotFinished(); return; } addMetaData ("content-length", KIO::number (m_totalSize)); TransferJob::start (slave); } void PostJob::slotDataReq() { assert(_dataSource); // If we reached the end of the device, indicate the condition // to the io-slave and reset the device position to 0 so that // the data can be re-transmitted if the io-slave requests it // again... if (_dataSource->atEnd()) { _dataSource->reset(); staticData = QByteArray(); _bytesSent = 0; kdDebug (7007) << "PostJob::slotDataReq: DONE => resetting data buffer..." << endl; } else { KIO::filesize_t dataSize = _blockSize; if ((m_totalSize - _bytesSent) < dataSize) dataSize = m_totalSize - _bytesSent; staticData.fill (0, dataSize); if (_dataSource->readBlock (staticData.data(), dataSize) < 0) { m_error = ERR_INTERNAL; m_errorText = i18n("PostJob::slotDataReq: Could not read POST data from source."); slotFinished (); kdDebug(7007) << "PostJob::slotDataReq: Error reading data..." << endl; return; } _bytesSent += dataSize; kdDebug (7007) << "PostJob::slotDataReq: Sent " << KIO::number(_bytesSent) << "/" << KIO::number(m_totalSize) << " bytes..." << endl; } TransferJob::slotDataReq(); } void PostJob::setEnablePortCheck (bool enable) { _validatePort = enable; } bool PostJob::isPortCheckEnabled () const { return _validatePort; } --Boundary-00=_WPFT+Wxaa7HhZsh Content-Type: text/x-c++src; charset="iso-8859-1"; name="postjob.hpp" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="postjob.hpp" /** * A job to stream data to the remote machine. * * @author Dawit Alemayehu */ class PostJob : public TransferJob { Q_OBJECT public: PostJob (const KURL& url, int command, const QByteArray& packedArgs, QIODevice * device, bool showProgressInfo); /** * @deprecated. This ctor is only provided for compatability sake * until all protocols that use KIO::http_post are ported to use * the newer API above. Use the above ctor instead. */ PostJob (const KURL& url, int command, const QByteArray& packedArgs, const QByteArray& data, bool showProgressInfo); ~PostJob (); /** * Set the size at which data is streamed (sent) to the io-slave. * The default block size (segement) is 256K. Due to the limitation * in the underlying framework (copying of data), the maximum size * allowed 1 MB. Any value above that will be truncated. * * @param size segement in bytes at which data should be sent to the * io-slave. */ void setBlockSize (KIO::filesize_t size); /** * @return the size in bytes of the data segement sent to an io-slave * at one time. */ KIO::filesize_t blockSize () const; /** * Re-implemented for internal reasons. API is unaffected. * * Note that the job will fail and return error if the POST action * is being done to a non-safe port. This of course depends on whether * non-safe port checking has been enabled or not. */ virtual void start (Slave* slave); /** * Enable/disable port verification to avoid maclicious posting. * Default is enabled. The default might not be applicable to all * protocols. If you rather do the checking yourself internally, * disable the check using this function. * * @param enable if true perform port check before starting a job. Do * not perform any checks otherwise. */ void setEnablePortCheck (bool enable); /** * @return true if non-safe port checking has been enabled. False otherwise. */ bool isPortCheckEnabled () const; protected: /** * Verifies whether or not the POST action is being done to a "safe" * (non-malicious) port number. * * @return true if port number is safe, false otherwise. */ virtual bool isPortSafe (); protected slots: /** * Re-implemented for internal reasons. API remains unaffected. */ virtual void slotDataReq (); private: KIO::filesize_t _bytesSent; KIO::filesize_t _blockSize; bool _autoDeleteSource; bool _validatePort; QIODevice* _dataSource; QString _tempfile; class HTTPPostPrivate* d; }; --Boundary-00=_WPFT+Wxaa7HhZsh--