-
Notifications
You must be signed in to change notification settings - Fork 6
/
timxmlrpc.vs2013.h
383 lines (302 loc) · 12.4 KB
/
timxmlrpc.vs2013.h
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
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
/*
XmlRpc C++ client for Windows
-----------------------------
Created by Dr Tim Cooper, [email protected], March 2009.
This lets you talk to web sites using XmlRpc from C++ on Windows. It differs
from similar libraries as follows:
- works on Windows
- supports HTTPS (SSL)
- uses wininet to manage HTTP/HTTPS, so it's really very minimal
- much faster than XmlRpc++ which suffers from STL performance problems.
This project consists of 2 files: "TimXmlRpc.h" and "TimXmlRpc.cpp".
Parts of this project have been taken from Chris Morley's "XmlRpc++" project,
in particular the API. Chris's contribution is acknowledged by marking his
work with the token: "/*ChrisMorley/". Thanks, Chris!
-------------------------Sample app:-------------------------
#include <iostream>
#include "timXmlRpc.h"
void Test(std::string username, std::string password)
{
XmlRpcValue args, result;
XmlRpcClient Connection("https://www.edval.com.au:9001/test.php");
args[0] = username;
args[1] = Md5(username + "." + password); // salted Md5
if (not Connection.execute("tetun.aprende", args, result)) {
std::cerr << "Error: " << Connection.getError() << std::endl;
}
else {
std::cout << "The answer is: " << std::string(result) << std::endl;
}
}
See 'SampleMain.cpp' for a more elaborate example.
*/
#include <string>
#include <vector>
#include <map>
#include <sstream>
typedef void (*XmlRpcCallback)(void* context, char* status);
/* A 'get username and password' function is used for HTTP basic authentication.
It will either get the (username,password) pair from some stored location, or
prompt the user for it.
Return 'true' if the user attempted to supply the credentials, or 'false'
if they want to cancel.
Display a 'logon failed' message if 'retry'.
*/
typedef bool (*getBasicAuth_UsernameAndPassword_fn)(bool retry, char username[256], char password[256]);
/* <Chris Morley> */
class XmlRpcException {
std::string _message;
public:
//! Constructor
//! @param message A descriptive error message
XmlRpcException(const std::string message) :
_message(message) {}
//! Return the error message.
const std::string& getMessage() const { return _message; }
};
/* </Chris Morley> */
class XmlRpcValue {
public:
/* <Chris Morley> */
enum Type {
TypeInvalid,
TypeBoolean,
TypeInt,
TypeDouble,
TypeString,
TypeDateTime,
TypeBase64,
TypeArray,
TypeStruct,
TypeNil
};
// Non-primitive types
typedef std::vector<char> BinaryData;
typedef std::map<std::string, XmlRpcValue> ValueStruct;
/* </Chris Morley> */
class ValueArray {
// tco> I'm implementing my own 'ValueArray' instead of the original
// std::vector<> because resizing the std::vector<> calls 100's of
// constructors and destructors. Using 'vector::reserve()' is not sufficient
// to prevent these constructors/destructors from being called, because
// the C++ standard requires constructors and destructors be called whenever
// an object changes its address, as happens when the std::vector resizes.
XmlRpcValue *A;
int _size;
int _allocated;
public:
ValueArray() { A = NULL; _size = _allocated = 0; }
ValueArray(int n) {
A = NULL; _size = _allocated = 0;
resize(n); }
ValueArray(ValueArray &other);
int size() { return _size; }
void resize(int n);
XmlRpcValue& operator[](int i) { return A[i]; }
XmlRpcValue& at(int i) { return A[i]; }
bool operator==(ValueArray &other);
void push_back(XmlRpcValue &val) { int last = _size; resize(_size + 1); A[last] = val; }
~ValueArray();
};
/* <Chris Morley> */
//! Constructors
XmlRpcValue() : _type(TypeInvalid) { u.asBinary = 0; }
XmlRpcValue(bool value) : _type(TypeBoolean) { u.asBool = value; }
XmlRpcValue(int value) : _type(TypeInt) { u.asInt = value; }
XmlRpcValue(double value) : _type(TypeDouble) { u.asDouble = value; }
XmlRpcValue(char value) : _type(TypeString) {
u.asString = (char*)malloc(2);
u.asString[0] = value;
u.asString[1] = '\0';
}
XmlRpcValue(std::string const& value) : _type(TypeString)
{ u.asString = _strdup(value.c_str()); }
XmlRpcValue(const char* value) : _type(TypeString)
{ u.asString = _strdup(value); }
XmlRpcValue(struct tm* value) : _type(TypeDateTime)
{ u.asTime = new struct tm(*value); }
XmlRpcValue(void* value, int nBytes) : _type(TypeBase64)
{
u.asBinary = new BinaryData((char*)value, ((char*)value)+nBytes);
}
//! Copy
XmlRpcValue(XmlRpcValue const& rhs) : _type(TypeInvalid) { *this = rhs; }
//! Destructor (make virtual if you want to subclass)
/*virtual*/ ~XmlRpcValue() { invalidate(); }
//! Erase the current value
void clear() { invalidate(); }
// Operators
XmlRpcValue& operator=(bool rhs) { return operator=(XmlRpcValue(rhs)); }
XmlRpcValue& operator=(int const& rhs) { return operator=(XmlRpcValue(rhs)); }
XmlRpcValue& operator=(double const& rhs) { return operator=(XmlRpcValue(rhs)); }
XmlRpcValue& operator=(const char* rhs) { return operator=(XmlRpcValue(rhs)); }
XmlRpcValue& operator=(char rhs) { return operator=(XmlRpcValue(rhs)); }
XmlRpcValue& operator=(XmlRpcValue const& rhs); //<-- don't use copy constructors if you can avoid them!
// This does a deep copy. Often you can use references instead of using copy constructors.
bool operator==(XmlRpcValue const& other) const;
bool operator!=(XmlRpcValue const& other) const { return !(*this == other); }
// This is an alternative to operator std::string() that Aigner claims is needed for VS13
std::string GetStdString() {
if (_type == TypeInt) {
char tmp[80];
_itoa_s(u.asInt, tmp, 10); // itoa(u.asInt, tmp, 10);
return (std::string)tmp;
}
assertTypeOrInvalid(TypeString);
return std::string(u.asString);
}
// There are some basic type conversions here. This might mean that your
// program parses stuff that strictly speaking it should report as a type error.
operator bool() { assertTypeOrInvalid(TypeBoolean);
return u.asBool;
}
operator int() {
if (_type == TypeString && u.asString[0] >= '0' && u.asString[0] <= '9')
return atoi(u.asString);
if (_type == TypeDouble)
return (int)u.asDouble;
if (_type == TypeInt)
return u.asInt;
assertTypeOrInvalid(TypeInt);
return 0;
}
operator char() { assertTypeOrInvalid(TypeString); return *u.asString; }
operator double() { if (_type == TypeDouble)
return u.asDouble;
if (_type == TypeInt)
return u.asInt;
assertTypeOrInvalid(TypeDouble);
return 0;
}
operator const std::string& ()
{
if (_type == TypeInt)
{
char tmp[80];
_itoa_s(u.asInt, tmp, 10); // itoa(u.asInt, tmp, 10);
return std::move(std::string(tmp));
}
assertTypeOrInvalid(TypeString);
return std::move(std::string(u.asString));
}
operator const char*() { assertTypeOrInvalid(TypeString); return u.asString; }
operator BinaryData&() { assertTypeOrInvalid(TypeBase64); return *u.asBinary; }
operator struct tm&() { assertTypeOrInvalid(TypeDateTime); return *u.asTime; }
operator ValueStruct&() { assertTypeOrInvalid(TypeStruct); return *u.asStruct; } // good for iterating thru fields
XmlRpcValue const& operator[](int i) const {
assertArray(i+1); return u.asArray->at(i);
}
XmlRpcValue& operator[](int i) { assertArray(i+1); return u.asArray->at(i); }
XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*u.asStruct)[k]; }
XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*u.asStruct)[s]; }
// Accessors
//! Return true if the value has been set to something.
bool valid() const { return _type != TypeInvalid; }
//! Return the type of the value stored. \see Type.
Type const &getType() const { return _type; }
//! Return the size for string, base64, array, and struct values.
int size() const;
//! Set up this value as an array, if not already so. This function is optional,
// because an undefined value is converted to an array implicitly the first time
// you index it with an integer e.g. arg[0] = "hello"; , however if there's a
// chance your array will be zero length then this function is compulsory.
void initAsArray() { assertArray(0); }
//! Specify the size for array values. Array values will grow beyond this size if needed.
void setSize(int size) { assertArray(size); }
//! Check for the existence of a struct member by name.
bool hasMember(const std::string& name) const;
//! Decode xml. Destroys any existing value.
void fromXml(const char* &s);
//! Encode the Value in xml
void toXml(std::ostringstream &ostr) const;
// Formatting
//! Return the format used to write double values.
static std::string const& getDoubleFormat() { return _doubleFormat; }
//! Specify the format used to write double values.
static void setDoubleFormat(const char* f) { _doubleFormat = f; }
bool parseMethodResponse(const char* s);
void buildCall(const char* method, std::ostringstream &ostr) const;
protected:
// Clean up
void invalidate();
// Type checking
void assertTypeOrInvalid(Type t);
void assertArray(int size) const;
void assertArray(int size);
void assertStruct();
// XML decoding
void boolFromXml(const char* &s);
void intFromXml(const char* &s);
void doubleFromXml(const char* &s);
void stringFromXml(const char* &s);
void timeFromXml(const char* &s);
void binaryFromXml(const char* &s);
void arrayFromXml(const char* &s);
void structFromXml(const char* &s);
// XML encoding
void boolToXml(std::ostringstream &ostr) const;
void intToXml(std::ostringstream &ostr) const;
void doubleToXml(std::ostringstream &ostr) const;
void stringToXml(std::ostringstream &ostr) const;
void timeToXml(std::ostringstream &ostr) const;
void binaryToXml(std::ostringstream &ostr) const;
void arrayToXml(std::ostringstream &ostr) const;
void structToXml(std::ostringstream &ostr) const;
void nilToXml(std::ostringstream &ostr) const;
// Format strings
static std::string _doubleFormat;
// Type tag and values
Type _type;
union {
bool asBool;
int asInt;
double asDouble;
struct tm* asTime;
char* asString;
BinaryData* asBinary;
ValueArray* asArray;
ValueStruct* asStruct;
} u;
};
/* </Chris Morley> */
class XmlRpcClient {
class XmlRpcImplementation *secret;
public:
enum protocol_enum { XMLRPC_AUTO=0, XMLRPC_HTTP=1, XMLRPC_HTTPS=2 };
//! Construct a client and attempt to connect to the server at the specified host:port address
//! @param host The name of the remote machine hosting the server
//! @param port The port on the remote machine where the server is listening
//! @param object An optional object name to be sent in the HTTP GET header
XmlRpcClient(const char* server, int port, const char* object, protocol_enum protocol=XMLRPC_AUTO);
//! Construct a client and attempt to connect to the server at the specified URI.
//! @param URI (Commonly and previously known as "URL"): e.g. "https://www.edval.com.au:9001/test.php"
XmlRpcClient(const char* URI);
~XmlRpcClient() { close(); }
//! Execute the named procedure on the remote server.
//! @param method The name of the remote procedure to execute
//! @param params An array of the arguments for the method
//! @param result The result value to be returned to the client
//! @return true if the request was sent and a result received
//! (although the result might be a fault).
//!
//! Currently this is a synchronous (blocking) implementation (execute
//! does not return until it receives a response or an error). Use isFault()
//! to determine whether the result is a fault response.
bool execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result);
//! Returns true if the result of the last execute() was a fault response.
bool isFault() const;
// Set the details for a callback function
void setCallback(XmlRpcCallback Callback, void* context);
// Set a callback to pop up a dialog box to ask the user for credentials
void setBasicAuth_Callback(getBasicAuth_UsernameAndPassword_fn fn);
// If you already have the credentials, pass them in here.
void setBasicAuth_UsernameAndPassword(const char* username, const char* password);
// ignore the certificate authority on subsequent execute()'s.
void setIgnoreCertificateAuthority(bool value=true);
// Get and set error messages:
std::string getError();
void setError(std::string);
int getHttpErrorCode();
//! Close the connection
void close();
};