File: client.cpp

package info (click to toggle)
qxmlrpc 0.0.svn6-2
  • links: PTS
  • area: main
  • in suites: buster, jessie, jessie-kfreebsd, stretch, wheezy
  • size: 392 kB
  • ctags: 200
  • sloc: cpp: 1,621; python: 29; makefile: 23
file content (324 lines) | stat: -rw-r--r-- 8,827 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
// vim:tabstop=4:shiftwidth=4:foldmethod=marker:expandtab:cinoptions=(s,U1,m1
// Copyright (C) 2009 Dmytro Poplavskiy <dmitry.poplavsky@gmail.com>

#include "xmlrpc/client.h"
#include "xmlrpc/request.h"
#include "xmlrpc/response.h"

#include <qhttp.h>
#include <qbuffer.h>
#include <QtNetwork>
#include <QAuthenticator>

//#define XMLRPC_DEBUG

namespace  xmlrpc {

class Client::Private
{
public:
    QString hostName;
    quint16 port;
    QString path;

    QString userName;
    QString password;

    QString userAgent;

    QHttp *http;

    QAuthenticator proxyAuth;

    QMap<int,QBuffer*> serverResponses;
    QMap<int, QString> methodNames; // id->methodNames
};

/**
 * Constructs a XmlRPC client.
 */
Client::Client(QObject * parent)
: QObject( parent )
{
    d = new Private;
    d->port = 0;
    d->path = "/";
    d->userAgent = "QXMLRPC";
    d->http = new QHttp(this);

    connect( d->http, SIGNAL(requestFinished(int,bool)), SLOT(requestFinished(int,bool)) );

    connect( d->http, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
             this, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *) ) );

    connect( d->http, SIGNAL( authenticationRequired ( const QString &, quint16, QAuthenticator * ) ),
             this, SIGNAL( authenticationRequired ( const QString &, quint16, QAuthenticator * ) ) );
}

/**
 * Constructs a XmlRPC client for communication with XmlRPC
 * server running on host \a hostName \a port.
 */
Client::Client(const QString & hostName, quint16 port, QObject * parent)
: QObject( parent )
{
    d = new Private;
    setHost( hostName, port );

    //important: dissconnect all connection from http in destructor,
    //otherwise crashes are possible when other parts of Client::Private
    //is deleted before http
    connect( d->http, SIGNAL(requestFinished(int,bool)), SLOT(requestFinished(int,bool)) );
}

/**
 * Destroys the XmlRPC client.
 */
Client::~Client()
{
    // it's necessary to delete QHttp instance before Private instance
    // to be sure Client slots will not be called with already deleted Private data
    delete d->http;
    qDeleteAll( d->serverResponses );
    delete d;
}


/**
 * Sets the XML-RPC server that is used for requests to hostName
 * on port \a port and path \path.
 */
void Client::setHost( const QString & hostName, quint16 port, QString path )
{
    d->hostName = hostName;
    d->port = port;
    d->path = path;
    d->http->setHost( hostName, port );
}

/**
 * Enables HTTP proxy support, using the proxy server host on port port.
 * username and password can be provided if the proxy server
 * requires authentication.
 */
void Client::setProxy( const QString & host, int port, 
                    const QString & userName, const QString & password )
{

#ifdef XMLRPC_DEBUG
    qDebug() << "xmlrpc client: set proxy" << host << port << userName << password;
#endif

    d->http->setProxy( host, port, userName, password );
}

/**
 * Replaces the internal QTcpSocket that QHttp uses with socket.
 * This can be useful for adding https support with QtSslSocket.
 * 
 * Check
 * \l{http://trolltech.com/products/qt/addon/solutions/catalog/4/Utilities/qtsslsocket/}
 * and QHttp::setSocket() for more information.
 */
void Client::setSocket( QTcpSocket * socket )
{
    d->http->setSocket( socket );
}

/**
 * Set the user name userName and password password for XML-RPC
 * ( or http ) server that require authentication.
 */
void Client::setUser( const QString & userName, const QString & password )
{
    //d->http->setUser( userName, password );
    d->userName = userName;
    d->password = password;
}

/**
 * Set the user agent HTTP value instead of default "QXMLRPC"
 */
void Client::setUserAgent( const QString & userAgent )
{
    d->userAgent = userAgent;
}

/**
 * Call method methodName on server side with parameters list
 * params. Returns id of request, used in done() and failed()
 * signals.
 * 
 * The parameters order is changed in overloaded methods to
 * avoid situation when the only parameter is the list.
 * \code
 * QList<xmlrpc::Variant> parameter;
 * ...
 * int requestId = client->request( methodName, parameter );
 * \endcode
 * This leads to this method be called, with parameter treated
 * as parameters list. It's possible to fix this with next code:
 * \code
 * client->request( methodName, xmlrpc::Variant(parameter) );
 * \endcode
 * but to avoid such kind of bugs, the parameters order in
 * overloaded methods was changed.
 */
int Client::request( QList<Variant> params, QString methodName )
{
    QBuffer *outBuffer = new QBuffer;

    QByteArray data = Request(methodName,params).composeRequest();

    QHttpRequestHeader header("POST",d->path);
    header.setContentLength( data.size() );
    header.setContentType("text/xml");
    header.setValue( "User-Agent", d->userAgent );
    header.setValue( "Connection", "Keep-Alive");


    if ( !d->userName.isEmpty() ) {
        QByteArray authData = QString(d->userName + ":" + d->password).toUtf8();
        authData = authData.toBase64();
        authData = QByteArray("Basic ")+authData;
        header.setValue("Authorization", authData.data() );
    }

    //header.setValue("Connection", "close");

    header.setValue("host",d->hostName);

    //d->http->setHost( d->hostName, d->port );

    int id = d->http->request( header, data, outBuffer );
    d->serverResponses[id] = outBuffer;
    d->methodNames[id] = methodName;
    d->http->close();

#ifdef XMLRPC_DEBUG
    qDebug() << "xmlrpc request(" << id << "): " << methodName;
    qDebug() << Variant(params).pprint();
#endif

    return id;
}

/**
 * Call method methodName on server side with empty parameters
 * list. This is an overloaded member function, provided for
 * convenience.
 */
int Client::request( QString methodName )
{
    QList<xmlrpc::Variant> params;
    return request( params, methodName );
}

/**
 * Call method methodName on server side with one parameter.
 * This is an overloaded member function, provided for
 * convenience.
 */
int Client::request( QString methodName, Variant param1 )
{
    QList<xmlrpc::Variant> params;
    params << param1;
    return request( params, methodName );
}

/**
 * Call method methodName on server side with two parameters.
 * This is an overloaded member function, provided for
 * convenience.
 */
int Client::request( QString methodName, Variant param1, Variant param2 )
{
    QList<xmlrpc::Variant> params;
    params << param1 << param2;
    return request( params, methodName );
}

/**
 * Call method methodName on server side with three parameters.
 * This is an overloaded member function, provided for
 * convenience.
 */
int Client::request( QString methodName, Variant param1, Variant param2, Variant param3 )
{
    QList<xmlrpc::Variant> params;
    params << param1 << param2 << param3;
    return request( params, methodName );
}
/**
 * Call method methodName on server side with four parameters.
 * This is an overloaded member function, provided for
 * convenience.
 */
int Client::request( QString methodName, Variant param1, Variant param2, Variant param3, Variant param4 )
{
    QList<xmlrpc::Variant> params;
    params << param1 << param2 << param3 << param4;
    return request( params, methodName );
}

void Client::requestFinished(int id, bool error)
{
    if ( !d->serverResponses.count(id) ) {
        return;
    }

#ifdef XMLRPC_DEBUG
    qDebug() << "request" <<  d->methodNames[id] <<  "finished, id=" << id << ", isError:" << error;
#endif

    if ( error ) {
        //if ( d->serverResponses.count(id) )

        QBuffer *buffer = d->serverResponses.take(id);
        delete buffer;


        emit failed(id, -32300, d->http->errorString() );
        return;
    }

    if ( d->serverResponses.count(id) ) {
        QBuffer *buffer = d->serverResponses.take(id);
        QByteArray buf = buffer->buffer();

        //qDebug() << "xml-rpc server response:\n" << QString(buf);

        Response response;

        QString errorMessage;
        if ( response.setContent( buf, &errorMessage ) ) {
            Q_ASSERT( !response.isNull() );

            if ( response.isFault() ) {
                qDebug() << "request failed:" << response.faultCode() << response.faultString();
                emit failed(id, response.faultCode(), response.faultString() );
            } else {
#ifdef XMLRPC_DEBUG
                qDebug() << response.returnValue().pprint();
#endif
                emit done( id, response.returnValue() );
            }

        } else {

#ifdef XMLRPC_DEBUG
            qDebug() << "incorrect xmlrpc response:" << errorMessage;
            qDebug() << QString(buf);
#endif
            emit failed(id, -32600, "Server error: Invalid xml-rpc. \nNot conforming to spec.");
        }
        delete buffer;

    }
	
}


}