mirror of https://github.com/KLayout/klayout.git
libcurl substitute for Qt network.
Reasoning: on Qt <4.7, custom request are not available. They are required however to implement WebDAV. libcurl provides a substitute for QNetwork. This is important for deployment on CentOS6 for example.
This commit is contained in:
parent
4c4b079286
commit
080623ad15
|
|
@ -43,6 +43,11 @@ equals(HAVE_PYTHON, "1") {
|
|||
DEFINES += HAVE_PYTHON
|
||||
}
|
||||
|
||||
equals(HAVE_CURL, "1") {
|
||||
DEFINES += HAVE_CURL
|
||||
LIBS += -lcurl
|
||||
}
|
||||
|
||||
equals(HAVE_RUBY, "1") {
|
||||
DEFINES += \
|
||||
HAVE_RUBY \
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ HEADERS = \
|
|||
layFontController.h \
|
||||
layNativePlugin.h \
|
||||
laySystemPaths.h \
|
||||
layMacroEditorSetupPage.h
|
||||
layMacroEditorSetupPage.h \
|
||||
layPasswordDialog.h
|
||||
|
||||
FORMS = \
|
||||
ClipDialog.ui \
|
||||
|
|
@ -105,7 +106,8 @@ FORMS = \
|
|||
SaltGrainTemplateSelectionDialog.ui \
|
||||
SaltManagerInstallConfirmationDialog.ui \
|
||||
CustomizeMenuConfigPage.ui \
|
||||
MacroEditorSetupPage.ui
|
||||
MacroEditorSetupPage.ui \
|
||||
PasswordDialog.ui
|
||||
|
||||
SOURCES = \
|
||||
gsiDeclLayApplication.cc \
|
||||
|
|
@ -160,7 +162,8 @@ SOURCES = \
|
|||
layFontController.cc \
|
||||
layNativePlugin.cc \
|
||||
laySystemPaths.cc \
|
||||
layMacroEditorSetupPage.cc
|
||||
layMacroEditorSetupPage.cc \
|
||||
layPasswordDialog.cc
|
||||
|
||||
RESOURCES = layBuildInMacros.qrc \
|
||||
layHelpResources.qrc \
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "layTechnologyController.h"
|
||||
#include "laySaltController.h"
|
||||
#include "laySystemPaths.h"
|
||||
#include "layPasswordDialog.h"
|
||||
#include "lymMacro.h"
|
||||
#include "gtf.h"
|
||||
#include "gsiDecl.h"
|
||||
|
|
@ -56,6 +57,7 @@
|
|||
#include "tlExpression.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlHttpStream.h"
|
||||
#include "tlArch.h"
|
||||
|
||||
#include <QIcon>
|
||||
|
|
@ -1520,6 +1522,10 @@ GuiApplication::setup ()
|
|||
|
||||
mp_mw = new lay::MainWindow (this, "main_window");
|
||||
QObject::connect (mp_mw, SIGNAL (closed ()), this, SLOT (quit ()));
|
||||
|
||||
// create a password dialog for use with the HTTP streams
|
||||
lay::PasswordDialog *pw_dialog = new lay::PasswordDialog (mp_mw);
|
||||
tl::InputHttpStream::set_credential_provider (pw_dialog);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "layPasswordDialog.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
PasswordDialog::PasswordDialog (QWidget *parent)
|
||||
: QDialog (parent)
|
||||
{
|
||||
setupUi (this);
|
||||
}
|
||||
|
||||
bool
|
||||
PasswordDialog::user_password (const std::string &url, const std::string &realm, bool proxy, int attempt, std::string &user, std::string &passwd)
|
||||
{
|
||||
realm_label->setText (tr ("<b>Realm:</b> ") + tl::to_qstring (realm));
|
||||
if (proxy) {
|
||||
where_label->setText (tr ("<b>Proxy:</b> ") + tl::to_qstring (url));
|
||||
} else {
|
||||
where_label->setText (tr ("<b>URL:</b> ") + tl::to_qstring (url));
|
||||
}
|
||||
|
||||
if (attempt > 1) {
|
||||
attempt_label->setText (tr ("Authentication failed - please try again"));
|
||||
attempt_label->show ();
|
||||
} else {
|
||||
attempt_label->hide ();
|
||||
}
|
||||
|
||||
if (QDialog::exec ()) {
|
||||
passwd = tl::to_string (password_le->text ());
|
||||
user = tl::to_string (user_le->text ());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_layPasswordDialog
|
||||
#define HDR_layPasswordDialog
|
||||
|
||||
#include "tlHttpStream.h"
|
||||
|
||||
#include "ui_PasswordDialog.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A password dialog for registration with tl::HttpStream
|
||||
*/
|
||||
class PasswordDialog
|
||||
: public QDialog, public tl::HttpCredentialProvider, private Ui::PasswordDialog
|
||||
{
|
||||
public:
|
||||
PasswordDialog (QWidget *parent);
|
||||
|
||||
bool user_password (const std::string &url, const std::string &realm, bool proxy, int attempt, std::string &user, std::string &passwd);
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -8,8 +8,7 @@ DEFINES += MAKE_TL_LIBRARY
|
|||
|
||||
LIBS += -lz
|
||||
|
||||
FORMS = \
|
||||
PasswordDialog.ui
|
||||
FORMS =
|
||||
|
||||
SOURCES = \
|
||||
tlAssert.cc \
|
||||
|
|
@ -43,7 +42,9 @@ SOURCES = \
|
|||
tlArch.cc \
|
||||
tlCommandLineParser.cc \
|
||||
tlUnitTest.cc \
|
||||
tlInt128Support.cc
|
||||
tlInt128Support.cc \
|
||||
tlHttpStreamCurl.cc \
|
||||
tlHttpStreamQt.cc
|
||||
|
||||
HEADERS = \
|
||||
tlAlgorithm.h \
|
||||
|
|
@ -92,7 +93,9 @@ HEADERS = \
|
|||
tlArch.h \
|
||||
tlCommandLineParser.h \
|
||||
tlUnitTest.h \
|
||||
tlInt128Support.h
|
||||
tlInt128Support.h \
|
||||
tlHttpStreamCurl.h \
|
||||
tlHttpStreamQt.h
|
||||
|
||||
INCLUDEPATH =
|
||||
DEPENDPATH =
|
||||
|
|
|
|||
|
|
@ -22,287 +22,10 @@
|
|||
|
||||
|
||||
#include "tlHttpStream.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlStaticObjects.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
|
||||
#include "ui_PasswordDialog.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkProxy>
|
||||
#include <QAuthenticator>
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QFileInfo>
|
||||
#include <QDialog>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// PasswordDialog definition and implementation
|
||||
|
||||
class PasswordDialog
|
||||
: public QDialog, private Ui::PasswordDialog
|
||||
{
|
||||
public:
|
||||
PasswordDialog (QWidget *parent)
|
||||
: QDialog (parent)
|
||||
{
|
||||
setupUi (this);
|
||||
}
|
||||
|
||||
bool exec_auth (bool proxy, int attempt, const QString &where, QAuthenticator *auth)
|
||||
{
|
||||
realm_label->setText (tr ("<b>Realm:</b> ") + auth->realm ());
|
||||
if (proxy) {
|
||||
where_label->setText (tr ("<b>Proxy:</b> ") + where);
|
||||
} else {
|
||||
where_label->setText (tr ("<b>URL:</b> ") + where);
|
||||
}
|
||||
|
||||
if (attempt > 1) {
|
||||
attempt_label->setText (tr ("Authentication failed - please try again"));
|
||||
attempt_label->show ();
|
||||
} else {
|
||||
attempt_label->hide ();
|
||||
}
|
||||
|
||||
if (QDialog::exec ()) {
|
||||
auth->setPassword (password_le->text ());
|
||||
auth->setUser (user_le->text ());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// AuthenticationHandler implementation
|
||||
|
||||
AuthenticationHandler::AuthenticationHandler ()
|
||||
: QObject (0), m_retry (0), m_proxy_retry (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
AuthenticationHandler::reset ()
|
||||
{
|
||||
m_retry = 0;
|
||||
m_proxy_retry = 0;
|
||||
}
|
||||
|
||||
void
|
||||
AuthenticationHandler::authenticationRequired (QNetworkReply *reply, QAuthenticator *auth)
|
||||
{
|
||||
PasswordDialog pw_dialog (0 /*no parent*/);
|
||||
pw_dialog.exec_auth (false, ++m_retry, reply->url ().toString (), auth);
|
||||
}
|
||||
|
||||
void
|
||||
AuthenticationHandler::proxyAuthenticationRequired (const QNetworkProxy &proxy, QAuthenticator *auth)
|
||||
{
|
||||
PasswordDialog pw_dialog (0 /*no parent*/);
|
||||
pw_dialog.exec_auth (true, ++m_proxy_retry, proxy.hostName (), auth);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// InputHttpFile implementation
|
||||
|
||||
static QNetworkAccessManager *s_network_manager (0);
|
||||
static AuthenticationHandler *s_auth_handler (0);
|
||||
|
||||
InputHttpStream::InputHttpStream (const std::string &url)
|
||||
: m_url (url), mp_reply (0), m_request ("GET"), mp_buffer (0)
|
||||
{
|
||||
if (! s_network_manager) {
|
||||
|
||||
s_network_manager = new QNetworkAccessManager (0);
|
||||
s_auth_handler = new AuthenticationHandler ();
|
||||
connect (s_network_manager, SIGNAL (authenticationRequired (QNetworkReply *, QAuthenticator *)), s_auth_handler, SLOT (authenticationRequired (QNetworkReply *, QAuthenticator *)));
|
||||
connect (s_network_manager, SIGNAL (proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *)), s_auth_handler, SLOT (proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *)));
|
||||
|
||||
tl::StaticObjects::reg (&s_network_manager);
|
||||
tl::StaticObjects::reg (&s_auth_handler);
|
||||
|
||||
}
|
||||
|
||||
connect (s_network_manager, SIGNAL (finished (QNetworkReply *)), this, SLOT (finished (QNetworkReply *)));
|
||||
}
|
||||
|
||||
InputHttpStream::~InputHttpStream ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::set_request (const char *r)
|
||||
{
|
||||
m_request = QByteArray (r);
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::set_data (const char *data)
|
||||
{
|
||||
m_data = QByteArray (data);
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::set_data (const char *data, size_t n)
|
||||
{
|
||||
m_data = QByteArray (data, int (n));
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::add_header (const std::string &name, const std::string &value)
|
||||
{
|
||||
m_headers.insert (std::make_pair (name, value));
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::finished (QNetworkReply *reply)
|
||||
{
|
||||
if (reply != mp_active_reply.get ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant redirect_target = reply->attribute (QNetworkRequest::RedirectionTargetAttribute);
|
||||
if (reply->error () == QNetworkReply::NoError && ! redirect_target.isNull ()) {
|
||||
m_url = tl::to_string (redirect_target.toString ());
|
||||
if (tl::verbosity() >= 30) {
|
||||
tl::info << "HTTP redirect to: " << m_url;
|
||||
}
|
||||
issue_request (QUrl (redirect_target.toString ()));
|
||||
} else {
|
||||
mp_reply = reply;
|
||||
m_ready ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::issue_request (const QUrl &url)
|
||||
{
|
||||
delete mp_buffer;
|
||||
mp_buffer = 0;
|
||||
|
||||
// reset the retry counters -> this way we can detect authentication failures
|
||||
s_auth_handler->reset ();
|
||||
|
||||
QNetworkRequest request (url);
|
||||
if (tl::verbosity() >= 30) {
|
||||
tl::info << "HTTP request URL: " << url.toString ().toUtf8 ().constData ();
|
||||
}
|
||||
for (std::map<std::string, std::string>::const_iterator h = m_headers.begin (); h != m_headers.end (); ++h) {
|
||||
if (tl::verbosity() >= 40) {
|
||||
tl::info << "HTTP request header: " << h->first << ": " << h->second;
|
||||
}
|
||||
request.setRawHeader (QByteArray (h->first.c_str ()), QByteArray (h->second.c_str ()));
|
||||
}
|
||||
|
||||
#if QT_VERSION < 0x40700
|
||||
if (m_request == "GET" && m_data.isEmpty ()) {
|
||||
mp_active_reply.reset (s_network_manager->get (request));
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Custom HTTP requests are not supported in this build (verb is %1)").arg (QString::fromUtf8 (m_request))));
|
||||
}
|
||||
#else
|
||||
if (m_data.isEmpty ()) {
|
||||
mp_active_reply.reset (s_network_manager->sendCustomRequest (request, m_request));
|
||||
} else {
|
||||
if (tl::verbosity() >= 40) {
|
||||
tl::info << "HTTP request data: " << m_data.constData ();
|
||||
}
|
||||
mp_buffer = new QBuffer (&m_data);
|
||||
mp_active_reply.reset (s_network_manager->sendCustomRequest (request, m_request, mp_buffer));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::send ()
|
||||
{
|
||||
if (mp_reply == 0) {
|
||||
issue_request (QUrl (tl::to_qstring (m_url)));
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
InputHttpStream::read (char *b, size_t n)
|
||||
{
|
||||
// Prevents deferred methods to be executed during the processEvents below (undesired side effects)
|
||||
tl::NoDeferredMethods silent;
|
||||
|
||||
if (mp_reply == 0) {
|
||||
issue_request (QUrl (tl::to_qstring (m_url)));
|
||||
}
|
||||
|
||||
// TODO: progress, timeout
|
||||
while (mp_reply == 0) {
|
||||
QCoreApplication::processEvents (QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
|
||||
if (mp_reply->error () != QNetworkReply::NoError) {
|
||||
|
||||
// throw an error
|
||||
std::string em = tl::to_string (mp_reply->attribute (QNetworkRequest::HttpReasonPhraseAttribute).toString ());
|
||||
if (tl::verbosity() >= 30) {
|
||||
tl::info << "HTTP response error: " << em;
|
||||
}
|
||||
|
||||
int ec = mp_reply->attribute (QNetworkRequest::HttpStatusCodeAttribute).toInt ();
|
||||
if (ec == 0) {
|
||||
switch (mp_reply->error ()) {
|
||||
case QNetworkReply::ConnectionRefusedError:
|
||||
em = tl::to_string (QObject::tr ("Connection refused"));
|
||||
break;
|
||||
case QNetworkReply::RemoteHostClosedError:
|
||||
em = tl::to_string (QObject::tr ("Remote host closed connection"));
|
||||
break;
|
||||
case QNetworkReply::HostNotFoundError:
|
||||
em = tl::to_string (QObject::tr ("Host not found"));
|
||||
break;
|
||||
case QNetworkReply::TimeoutError:
|
||||
em = tl::to_string (QObject::tr ("Timeout"));
|
||||
break;
|
||||
case QNetworkReply::ContentAccessDenied:
|
||||
em = tl::to_string (QObject::tr ("Access denied"));
|
||||
break;
|
||||
case QNetworkReply::ContentNotFoundError:
|
||||
em = tl::to_string (QObject::tr ("Content not found"));
|
||||
break;
|
||||
default:
|
||||
em = tl::to_string (QObject::tr ("Network API error"));
|
||||
}
|
||||
ec = int (mp_reply->error ());
|
||||
}
|
||||
|
||||
throw HttpErrorException (em, ec, m_url);
|
||||
|
||||
}
|
||||
|
||||
QByteArray data = mp_reply->read (n);
|
||||
memcpy (b, data.constData (), data.size ());
|
||||
if (tl::verbosity() >= 40) {
|
||||
tl::info << "HTTP reponse data read: " << data.constData ();
|
||||
}
|
||||
return data.size ();
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::reset ()
|
||||
{
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("'reset' is not supported on HTTP input streams")));
|
||||
}
|
||||
|
||||
std::string
|
||||
InputHttpStream::filename () const
|
||||
{
|
||||
return tl::to_string (QFileInfo (QUrl (tl::to_qstring (m_url)).path ()).fileName ());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,26 +20,36 @@
|
|||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_tlHttpStream
|
||||
#define HDR_tlHttpStream
|
||||
|
||||
#include "tlStream.h"
|
||||
#include "tlEvents.h"
|
||||
#include "tlHttpStreamCurl.h"
|
||||
#include "tlHttpStreamQt.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QBuffer>
|
||||
#include <QByteArray>
|
||||
#include <memory>
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class QNetworkProxy;
|
||||
class QAuthenticator;
|
||||
#include "tlObject.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A callback interface to provide the authentication data
|
||||
*/
|
||||
class TL_PUBLIC HttpCredentialProvider
|
||||
: public tl::Object
|
||||
{
|
||||
public:
|
||||
HttpCredentialProvider () { }
|
||||
virtual ~HttpCredentialProvider () { }
|
||||
|
||||
/**
|
||||
* @brief Gets the user name and password for the given URL and authentication realm
|
||||
*/
|
||||
virtual bool user_password (const std::string &url, const std::string &realm, bool proxy, int attempt, std::string &user, std::string &passwd) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An exception class for HTTP errors
|
||||
*/
|
||||
class TL_PUBLIC HttpErrorException
|
||||
: public tl::Exception
|
||||
{
|
||||
|
|
@ -49,137 +59,6 @@ public:
|
|||
{ }
|
||||
};
|
||||
|
||||
class AuthenticationHandler
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AuthenticationHandler ();
|
||||
|
||||
public slots:
|
||||
void authenticationRequired (QNetworkReply *, QAuthenticator *);
|
||||
void proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *);
|
||||
void reset ();
|
||||
|
||||
private:
|
||||
int m_retry, m_proxy_retry;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A http input delegate for tl::InputStream
|
||||
*
|
||||
* Implements the reader from a server using the HTTP protocol
|
||||
*/
|
||||
class TL_PUBLIC InputHttpStream
|
||||
: public QObject, public InputStreamBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Open a stream with the given URL
|
||||
*/
|
||||
InputHttpStream (const std::string &url);
|
||||
|
||||
/**
|
||||
* @brief Close the file
|
||||
*
|
||||
* The destructor will automatically close the connection.
|
||||
*/
|
||||
virtual ~InputHttpStream ();
|
||||
|
||||
/**
|
||||
* @brief Sends the request for data
|
||||
* To ensure prompt delivery of data, this method can be used prior to
|
||||
* "read" to trigger the download from the given URL.
|
||||
* This method will return immediately. When the reply is available,
|
||||
* the "ready" event will be triggered. "read" can then be used to
|
||||
* read the data or - in case of an error - throw an exception.
|
||||
* If "send" is not used before "read", "read" will block until data
|
||||
* is available.
|
||||
* If a request has already been sent, this method will do nothing.
|
||||
*/
|
||||
void send ();
|
||||
|
||||
/**
|
||||
* @brief Sets the request verb
|
||||
* The default verb is "GET"
|
||||
*/
|
||||
void set_request (const char *r);
|
||||
|
||||
/**
|
||||
* @brief Sets data to be sent with the request
|
||||
* If data is given, it is sent along with the request.
|
||||
* This version takes a null-terminated string.
|
||||
*/
|
||||
void set_data (const char *data);
|
||||
|
||||
/**
|
||||
* @brief Sets data to be sent with the request
|
||||
* If data is given, it is sent along with the request.
|
||||
* This version takes a data plus length.
|
||||
*/
|
||||
void set_data (const char *data, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Sets a header field
|
||||
*/
|
||||
void add_header (const std::string &name, const std::string &value);
|
||||
|
||||
/**
|
||||
* @brief Read from the stream
|
||||
* Implements the basic read method.
|
||||
*/
|
||||
virtual size_t read (char *b, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Gets the "ready" event
|
||||
* Connect to this event for the asynchroneous interface.
|
||||
*/
|
||||
tl::Event &ready ()
|
||||
{
|
||||
return m_ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether data is available
|
||||
*/
|
||||
bool data_available ()
|
||||
{
|
||||
return mp_reply != 0;
|
||||
}
|
||||
|
||||
virtual void reset ();
|
||||
|
||||
virtual std::string source () const
|
||||
{
|
||||
return m_url;
|
||||
}
|
||||
|
||||
virtual std::string absolute_path () const
|
||||
{
|
||||
return m_url;
|
||||
}
|
||||
|
||||
virtual std::string filename () const;
|
||||
|
||||
private slots:
|
||||
void finished (QNetworkReply *);
|
||||
|
||||
private:
|
||||
std::string m_url;
|
||||
QNetworkReply *mp_reply;
|
||||
std::auto_ptr<QNetworkReply> mp_active_reply;
|
||||
QByteArray m_request;
|
||||
QByteArray m_data;
|
||||
QBuffer *mp_buffer;
|
||||
std::map<std::string, std::string> m_headers;
|
||||
tl::Event m_ready;
|
||||
|
||||
void issue_request (const QUrl &url);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,144 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_tlHttpStreamCurl
|
||||
#define HDR_tlHttpStreamCurl
|
||||
|
||||
#if defined(HAVE_CURL)
|
||||
|
||||
#include "tlStream.h"
|
||||
#include "tlEvents.h"
|
||||
#include "tlObject.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
class CurlConnection;
|
||||
class HttpCredentialProvider;
|
||||
|
||||
/**
|
||||
* @brief A http input delegate for tl::InputStream
|
||||
*
|
||||
* Implements the reader from a server using the HTTP protocol
|
||||
*/
|
||||
class TL_PUBLIC InputHttpStream
|
||||
// NOTE: QObject is required because we use "deleteLater"
|
||||
: public QObject, public tl::Object, public InputStreamBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Open a stream with the given URL
|
||||
*/
|
||||
InputHttpStream (const std::string &url);
|
||||
|
||||
/**
|
||||
* @brief Close the file
|
||||
*
|
||||
* The destructor will automatically close the connection.
|
||||
*/
|
||||
virtual ~InputHttpStream ();
|
||||
|
||||
/**
|
||||
* @brief Sets the credential provider
|
||||
*/
|
||||
static void set_credential_provider (HttpCredentialProvider *cp);
|
||||
|
||||
/**
|
||||
* @brief Sends the request for data
|
||||
* To ensure prompt delivery of data, this method can be used prior to
|
||||
* "read" to trigger the download from the given URL.
|
||||
* This method will return immediately. When the reply is available,
|
||||
* the "ready" event will be triggered. "read" can then be used to
|
||||
* read the data or - in case of an error - throw an exception.
|
||||
* If "send" is not used before "read", "read" will block until data
|
||||
* is available.
|
||||
* If a request has already been sent, this method will do nothing.
|
||||
*/
|
||||
void send ();
|
||||
|
||||
/**
|
||||
* @brief Sets the request verb
|
||||
* The default verb is "GET"
|
||||
*/
|
||||
void set_request (const char *r);
|
||||
|
||||
/**
|
||||
* @brief Sets data to be sent with the request
|
||||
* If data is given, it is sent along with the request.
|
||||
* This version takes a null-terminated string.
|
||||
*/
|
||||
void set_data (const char *data);
|
||||
|
||||
/**
|
||||
* @brief Sets data to be sent with the request
|
||||
* If data is given, it is sent along with the request.
|
||||
* This version takes a data plus length.
|
||||
*/
|
||||
void set_data (const char *data, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Sets a header field
|
||||
*/
|
||||
void add_header (const std::string &name, const std::string &value);
|
||||
|
||||
/**
|
||||
* @brief Read from the stream
|
||||
* Implements the basic read method.
|
||||
*/
|
||||
virtual size_t read (char *b, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Gets the "ready" event
|
||||
* Connect to this event for the asynchroneous interface.
|
||||
*/
|
||||
tl::Event &ready ()
|
||||
{
|
||||
return m_ready_event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether data is available
|
||||
*/
|
||||
bool data_available ();
|
||||
|
||||
virtual void reset ();
|
||||
|
||||
virtual std::string source () const;
|
||||
virtual std::string absolute_path () const;
|
||||
virtual std::string filename () const;
|
||||
|
||||
private:
|
||||
std::auto_ptr<CurlConnection> m_connection;
|
||||
tl::Event m_ready_event;
|
||||
bool m_sent;
|
||||
|
||||
void finished ();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_CURL)
|
||||
|
||||
#include "tlHttpStream.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlStaticObjects.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
#include "tlObject.h"
|
||||
|
||||
#include "ui_PasswordDialog.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkProxy>
|
||||
#include <QAuthenticator>
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QFileInfo>
|
||||
#include <QDialog>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
tl::weak_ptr<HttpCredentialProvider> sp_credential_provider;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// AuthenticationHandler implementation
|
||||
|
||||
AuthenticationHandler::AuthenticationHandler ()
|
||||
: QObject (0), m_retry (0), m_proxy_retry (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
AuthenticationHandler::reset ()
|
||||
{
|
||||
m_retry = 0;
|
||||
m_proxy_retry = 0;
|
||||
}
|
||||
|
||||
void
|
||||
AuthenticationHandler::authenticationRequired (QNetworkReply *reply, QAuthenticator *auth)
|
||||
{
|
||||
if (sp_credential_provider.get ()) {
|
||||
|
||||
// TODO: how to cancel?
|
||||
std::string user, passwd;
|
||||
if (sp_credential_provider->user_password (tl::to_string (reply->url ().toString ()), tl::to_string (auth->realm ()), true, ++m_retry, user, passwd)) {
|
||||
auth->setPassword (tl::to_qstring (passwd));
|
||||
auth->setUser (tl::to_qstring (user));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AuthenticationHandler::proxyAuthenticationRequired (const QNetworkProxy &proxy, QAuthenticator *auth)
|
||||
{
|
||||
if (sp_credential_provider.get ()) {
|
||||
|
||||
// TODO: how to cancel?
|
||||
std::string user, passwd;
|
||||
if (sp_credential_provider->user_password (tl::to_string (proxy.hostName ()), tl::to_string (auth->realm ()), true, ++m_proxy_retry, user, passwd)) {
|
||||
auth->setPassword (tl::to_qstring (passwd));
|
||||
auth->setUser (tl::to_qstring (user));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// InputHttpFileQt implementation
|
||||
|
||||
static QNetworkAccessManager *s_network_manager (0);
|
||||
static AuthenticationHandler *s_auth_handler (0);
|
||||
|
||||
InputHttpStream::InputHttpStream (const std::string &url)
|
||||
: m_url (url), mp_reply (0), m_request ("GET"), mp_buffer (0)
|
||||
{
|
||||
if (! s_network_manager) {
|
||||
|
||||
s_network_manager = new QNetworkAccessManager (0);
|
||||
s_auth_handler = new AuthenticationHandler ();
|
||||
connect (s_network_manager, SIGNAL (authenticationRequired (QNetworkReply *, QAuthenticator *)), s_auth_handler, SLOT (authenticationRequired (QNetworkReply *, QAuthenticator *)));
|
||||
connect (s_network_manager, SIGNAL (proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *)), s_auth_handler, SLOT (proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *)));
|
||||
|
||||
tl::StaticObjects::reg (&s_network_manager);
|
||||
tl::StaticObjects::reg (&s_auth_handler);
|
||||
|
||||
}
|
||||
|
||||
connect (s_network_manager, SIGNAL (finished (QNetworkReply *)), this, SLOT (finished (QNetworkReply *)));
|
||||
}
|
||||
|
||||
InputHttpStream::~InputHttpStream ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::set_credential_provider (HttpCredentialProvider *cp)
|
||||
{
|
||||
sp_credential_provider.reset (cp);
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::set_request (const char *r)
|
||||
{
|
||||
m_request = QByteArray (r);
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::set_data (const char *data)
|
||||
{
|
||||
m_data = QByteArray (data);
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::set_data (const char *data, size_t n)
|
||||
{
|
||||
m_data = QByteArray (data, int (n));
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::add_header (const std::string &name, const std::string &value)
|
||||
{
|
||||
m_headers.insert (std::make_pair (name, value));
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::finished (QNetworkReply *reply)
|
||||
{
|
||||
if (reply != mp_active_reply.get ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant redirect_target = reply->attribute (QNetworkRequest::RedirectionTargetAttribute);
|
||||
if (reply->error () == QNetworkReply::NoError && ! redirect_target.isNull ()) {
|
||||
m_url = tl::to_string (redirect_target.toString ());
|
||||
if (tl::verbosity() >= 30) {
|
||||
tl::info << "HTTP redirect to: " << m_url;
|
||||
}
|
||||
issue_request (QUrl (redirect_target.toString ()));
|
||||
} else {
|
||||
mp_reply = reply;
|
||||
m_ready ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::issue_request (const QUrl &url)
|
||||
{
|
||||
delete mp_buffer;
|
||||
mp_buffer = 0;
|
||||
|
||||
// reset the retry counters -> this way we can detect authentication failures
|
||||
s_auth_handler->reset ();
|
||||
|
||||
QNetworkRequest request (url);
|
||||
if (tl::verbosity() >= 30) {
|
||||
tl::info << "HTTP request URL: " << url.toString ().toUtf8 ().constData ();
|
||||
}
|
||||
for (std::map<std::string, std::string>::const_iterator h = m_headers.begin (); h != m_headers.end (); ++h) {
|
||||
if (tl::verbosity() >= 40) {
|
||||
tl::info << "HTTP request header: " << h->first << ": " << h->second;
|
||||
}
|
||||
request.setRawHeader (QByteArray (h->first.c_str ()), QByteArray (h->second.c_str ()));
|
||||
}
|
||||
|
||||
#if QT_VERSION < 0x40700
|
||||
if (m_request == "GET" && m_data.isEmpty ()) {
|
||||
mp_active_reply.reset (s_network_manager->get (request));
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Custom HTTP requests are not supported in this build (verb is %1)").arg (QString::fromUtf8 (m_request))));
|
||||
}
|
||||
#else
|
||||
if (m_data.isEmpty ()) {
|
||||
mp_active_reply.reset (s_network_manager->sendCustomRequest (request, m_request));
|
||||
} else {
|
||||
if (tl::verbosity() >= 40) {
|
||||
tl::info << "HTTP request data: " << m_data.constData ();
|
||||
}
|
||||
mp_buffer = new QBuffer (&m_data);
|
||||
mp_active_reply.reset (s_network_manager->sendCustomRequest (request, m_request, mp_buffer));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::send ()
|
||||
{
|
||||
if (mp_reply == 0) {
|
||||
issue_request (QUrl (tl::to_qstring (m_url)));
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
InputHttpStream::read (char *b, size_t n)
|
||||
{
|
||||
// Prevents deferred methods to be executed during the processEvents below (undesired side effects)
|
||||
tl::NoDeferredMethods silent;
|
||||
|
||||
if (mp_reply == 0) {
|
||||
issue_request (QUrl (tl::to_qstring (m_url)));
|
||||
}
|
||||
|
||||
// TODO: progress, timeout
|
||||
while (mp_reply == 0) {
|
||||
QCoreApplication::processEvents (QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
|
||||
if (mp_reply->error () != QNetworkReply::NoError) {
|
||||
|
||||
// throw an error
|
||||
std::string em = tl::to_string (mp_reply->attribute (QNetworkRequest::HttpReasonPhraseAttribute).toString ());
|
||||
if (tl::verbosity() >= 30) {
|
||||
tl::info << "HTTP response error: " << em;
|
||||
}
|
||||
|
||||
int ec = mp_reply->attribute (QNetworkRequest::HttpStatusCodeAttribute).toInt ();
|
||||
if (ec == 0) {
|
||||
switch (mp_reply->error ()) {
|
||||
case QNetworkReply::ConnectionRefusedError:
|
||||
em = tl::to_string (QObject::tr ("Connection refused"));
|
||||
break;
|
||||
case QNetworkReply::RemoteHostClosedError:
|
||||
em = tl::to_string (QObject::tr ("Remote host closed connection"));
|
||||
break;
|
||||
case QNetworkReply::HostNotFoundError:
|
||||
em = tl::to_string (QObject::tr ("Host not found"));
|
||||
break;
|
||||
case QNetworkReply::TimeoutError:
|
||||
em = tl::to_string (QObject::tr ("Timeout"));
|
||||
break;
|
||||
case QNetworkReply::ContentAccessDenied:
|
||||
em = tl::to_string (QObject::tr ("Access denied"));
|
||||
break;
|
||||
case QNetworkReply::ContentNotFoundError:
|
||||
em = tl::to_string (QObject::tr ("Content not found"));
|
||||
break;
|
||||
default:
|
||||
em = tl::to_string (QObject::tr ("Network API error"));
|
||||
}
|
||||
ec = int (mp_reply->error ());
|
||||
}
|
||||
|
||||
throw HttpErrorException (em, ec, m_url);
|
||||
|
||||
}
|
||||
|
||||
QByteArray data = mp_reply->read (n);
|
||||
memcpy (b, data.constData (), data.size ());
|
||||
if (tl::verbosity() >= 40) {
|
||||
tl::info << "HTTP reponse data read: " << data.constData ();
|
||||
}
|
||||
return data.size ();
|
||||
}
|
||||
|
||||
void
|
||||
InputHttpStream::reset ()
|
||||
{
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("'reset' is not supported on HTTP input streams")));
|
||||
}
|
||||
|
||||
std::string
|
||||
InputHttpStream::filename () const
|
||||
{
|
||||
return tl::to_string (QFileInfo (QUrl (tl::to_qstring (m_url)).path ()).fileName ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_tlHttpStreamQt
|
||||
#define HDR_tlHttpStreamQt
|
||||
|
||||
#if !defined(HAVE_CURL)
|
||||
|
||||
#include "tlStream.h"
|
||||
#include "tlEvents.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QBuffer>
|
||||
#include <QByteArray>
|
||||
#include <memory>
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class QNetworkProxy;
|
||||
class QAuthenticator;
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
class HttpCredentialProvider;
|
||||
|
||||
class AuthenticationHandler
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AuthenticationHandler ();
|
||||
|
||||
public slots:
|
||||
void authenticationRequired (QNetworkReply *, QAuthenticator *);
|
||||
void proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *);
|
||||
void reset ();
|
||||
|
||||
private:
|
||||
int m_retry, m_proxy_retry;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A http input delegate for tl::InputStream
|
||||
*
|
||||
* Implements the reader from a server using the HTTP protocol
|
||||
*/
|
||||
class TL_PUBLIC InputHttpStream
|
||||
: public QObject, public InputStreamBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Open a stream with the given URL
|
||||
*/
|
||||
InputHttpStream (const std::string &url);
|
||||
|
||||
/**
|
||||
* @brief Close the file
|
||||
*
|
||||
* The destructor will automatically close the connection.
|
||||
*/
|
||||
virtual ~InputHttpStream ();
|
||||
|
||||
/**
|
||||
* @brief Sets the credential provider
|
||||
*/
|
||||
static void set_credential_provider (HttpCredentialProvider *cp);
|
||||
|
||||
/**
|
||||
* @brief Sends the request for data
|
||||
* To ensure prompt delivery of data, this method can be used prior to
|
||||
* "read" to trigger the download from the given URL.
|
||||
* This method will return immediately. When the reply is available,
|
||||
* the "ready" event will be triggered. "read" can then be used to
|
||||
* read the data or - in case of an error - throw an exception.
|
||||
* If "send" is not used before "read", "read" will block until data
|
||||
* is available.
|
||||
* If a request has already been sent, this method will do nothing.
|
||||
*/
|
||||
void send ();
|
||||
|
||||
/**
|
||||
* @brief Sets the request verb
|
||||
* The default verb is "GET"
|
||||
*/
|
||||
void set_request (const char *r);
|
||||
|
||||
/**
|
||||
* @brief Sets data to be sent with the request
|
||||
* If data is given, it is sent along with the request.
|
||||
* This version takes a null-terminated string.
|
||||
*/
|
||||
void set_data (const char *data);
|
||||
|
||||
/**
|
||||
* @brief Sets data to be sent with the request
|
||||
* If data is given, it is sent along with the request.
|
||||
* This version takes a data plus length.
|
||||
*/
|
||||
void set_data (const char *data, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Sets a header field
|
||||
*/
|
||||
void add_header (const std::string &name, const std::string &value);
|
||||
|
||||
/**
|
||||
* @brief Read from the stream
|
||||
* Implements the basic read method.
|
||||
*/
|
||||
virtual size_t read (char *b, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Gets the "ready" event
|
||||
* Connect to this event for the asynchroneous interface.
|
||||
*/
|
||||
tl::Event &ready ()
|
||||
{
|
||||
return m_ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether data is available
|
||||
*/
|
||||
bool data_available ()
|
||||
{
|
||||
return mp_reply != 0;
|
||||
}
|
||||
|
||||
virtual void reset ();
|
||||
|
||||
virtual std::string source () const
|
||||
{
|
||||
return m_url;
|
||||
}
|
||||
|
||||
virtual std::string absolute_path () const
|
||||
{
|
||||
return m_url;
|
||||
}
|
||||
|
||||
virtual std::string filename () const;
|
||||
|
||||
private slots:
|
||||
void finished (QNetworkReply *);
|
||||
|
||||
private:
|
||||
std::string m_url;
|
||||
QNetworkReply *mp_reply;
|
||||
std::auto_ptr<QNetworkReply> mp_active_reply;
|
||||
QByteArray m_request;
|
||||
QByteArray m_data;
|
||||
QBuffer *mp_buffer;
|
||||
std::map<std::string, std::string> m_headers;
|
||||
tl::Event m_ready;
|
||||
|
||||
void issue_request (const QUrl &url);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue