From: Stefan Bund Date: Fri, 10 Dec 2010 09:48:30 +0000 (+0100) Subject: POST data support X-Git-Url: http://g0dil.de/git?p=pykit.git;a=commitdiff_plain;h=5f68db2ece38a2e31a9acd884a96194e33b9c430 POST data support --- diff --git a/Publisher.cc b/Publisher.cc index 7176b7c..23eb5bf 100644 --- a/Publisher.cc +++ b/Publisher.cc @@ -32,7 +32,7 @@ namespace detail { public: InternalServerReply(QNetworkAccessManager::Operation operation, QNetworkRequest const & networkRequest, - Publisher * publisher); + QIODevice * postData, Publisher * publisher); // Forwarded to buffer virtual bool atEnd() const; @@ -52,26 +52,36 @@ namespace detail { using QNetworkReply::setHeader; void clearResponse(); + QByteArray postData() const; + QString postContentType() const; protected: virtual qint64 readData(char * data, qint64 maxSize); virtual qint64 writeData(char const * data, qint64 maxSize); - signals: - void initSignal(); - private slots: - void initSlot(); + void bufferPostData(); + void postDataReadable(); + void postDataComplete(); + void processRequest(); + void complete(); private: + bool readPostData(); + + Publisher * publisher_; + QIODevice * postDevice_; QBuffer buffer_; + QBuffer postData_; }; }} prefix_ pykit::detail::InternalServerReply:: InternalServerReply(QNetworkAccessManager::Operation operation, - QNetworkRequest const & networkRequest, Publisher * publisher) + QNetworkRequest const & networkRequest, QIODevice * postData, + Publisher * publisher) + : publisher_ (publisher), postDevice_ (postData) { setRequest(networkRequest); setOperation(operation); @@ -79,25 +89,74 @@ InternalServerReply(QNetworkAccessManager::Operation operation, open(ReadWrite | Unbuffered); buffer_.open(ReadWrite | Unbuffered); + if (postDevice_) + QMetaObject::invokeMethod(this, "bufferPostData", Qt::QueuedConnection); + else + QMetaObject::invokeMethod(this, "processRequest", Qt::QueuedConnection); +} + +prefix_ void pykit::detail::InternalServerReply::bufferPostData() +{ + QVariant cl (request().header(QNetworkRequest::ContentLengthHeader)); + std::cerr << "postdata contentlength: " << (cl.isValid() ? cl.toString().toStdString() : "invalid") << "\n"; + connect(postDevice_, SIGNAL(readyRead()), this, SLOT(postDataReadable())); + connect(postDevice_, SIGNAL(readChannelFinished()), this, SLOT(postDataComplete())); + postData_.open(WriteOnly); + postDataReadable(); +} + +prefix_ bool pykit::detail::InternalServerReply::readPostData() +{ + while (true) { + qint64 n (postDevice_->bytesAvailable()); + if (n <= 0) + n = 2048; + QByteArray data; + data.resize(n); + n = postDevice_->read(data.data(), n); + if (n < 0) + return true; + else { + data.resize(n); + postData_.write(data); + } + if (n == 0) + return false; + } +} + +prefix_ void pykit::detail::InternalServerReply::postDataReadable() +{ + if (readPostData()) { + disconnect(postDevice_, SIGNAL(readyRead()), this, SLOT(postDataReadable())); + disconnect(postDevice_, SIGNAL(readChannelFinished()), this, SLOT(postDataComplete())); + processRequest(); + } +} + +prefix_ void pykit::detail::InternalServerReply::postDataComplete() +{ + readPostData(); + disconnect(postDevice_, SIGNAL(readyRead()), this, SLOT(postDataReadable())); + disconnect(postDevice_, SIGNAL(readChannelFinished()), this, SLOT(postDataComplete())); + processRequest(); +} + +prefix_ void pykit::detail::InternalServerReply::processRequest() +{ Request request (*this); - publisher->publish(request); + publisher_->publish(request); seek(0); setHeader(QNetworkRequest::ContentLengthHeader, QVariant(size())); - setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/html; charset=UTF-8")); - // The following rigamole is needed to delay emitting readyRead() / finished() after until the - // connections to those signals have been set up. - // - // We use a queued signal here. This will call initSlot after processing has returned to the - // event loop. - connect(this, SIGNAL(initSignal()), this, SLOT(initSlot()), Qt::QueuedConnection); - emit initSignal(); + QMetaObject::invokeMethod(this, "complete", Qt::QueuedConnection); } -prefix_ void pykit::detail::InternalServerReply::initSlot() +prefix_ void pykit::detail::InternalServerReply::complete() { emit readyRead(); + emit readChannelFinished(); emit finished(); } @@ -155,6 +214,18 @@ prefix_ void pykit::detail::InternalServerReply::clearResponse() buffer_.buffer().clear(); } +prefix_ QByteArray pykit::detail::InternalServerReply::postData() + const +{ + return postData_.buffer(); +} + +prefix_ QString pykit::detail::InternalServerReply::postContentType() + const +{ + return request().header(QNetworkRequest::ContentTypeHeader).toString(); +} + /////////////////////////////////////////////////////////////////////////// // pykit::Request @@ -184,6 +255,26 @@ prefix_ QUrl pykit::Request::url() return reply_.url(); } +prefix_ QByteArray pykit::Request::postData() + const +{ + return reply_.postData(); +} + +prefix_ QByteArray pykit::Request::operation() + const +{ + static char const * const operationNames[] + = { "", "HEAD", "GET", "PUT", "POST", "DELETE", "" }; + return operationNames[reply_.operation()]; +} + +prefix_ QString pykit::Request::postContentType() + const +{ + return reply_.postContentType(); +} + prefix_ pykit::Request::Request(detail::InternalServerReply & reply) : reply_ (reply) {} @@ -210,7 +301,7 @@ pykit::InternalNetworkAccessManager::createRequest(Operation operation, if (request.url().scheme() != "srv") return QNetworkAccessManager::createRequest(operation, request, device); - return new detail::InternalServerReply(operation, request, publisher_); + return new detail::InternalServerReply(operation, request, device, publisher_); } #include "Publisher.moc" diff --git a/Publisher.hh b/Publisher.hh index 2fd4cba..46d7507 100644 --- a/Publisher.hh +++ b/Publisher.hh @@ -33,6 +33,9 @@ namespace pykit { void setLocation(std::string const & location); QUrl url() const; + QByteArray postData() const; + QByteArray operation() const; + QString postContentType() const; private: Request(detail::InternalServerReply & reply); diff --git a/PythonPublisher.cc b/PythonPublisher.cc index d71cdee..b045385 100644 --- a/PythonPublisher.cc +++ b/PythonPublisher.cc @@ -424,6 +424,9 @@ BOOST_PYTHON_MODULE(_pykit) .def("setContentType", &pykit::Request::setContentType) .def("setLocation", &pykit::Request::setLocation) .def("url", &pykit::Request::url) + .def("postData", &pykit::Request::postData) + .def("operation", &pykit::Request::operation) + .def("postContentType", &pykit::Request::postContentType) ; py::class_("Publisher")