392 lines
12 KiB
C++
392 lines
12 KiB
C++
|
// Copyright (C) 2001 by Eric Kidd. All rights reserved.
|
||
|
//
|
||
|
// Redistribution and use in source and binary forms, with or without
|
||
|
// modification, are permitted provided that the following conditions
|
||
|
// are met:
|
||
|
// 1. Redistributions of source code must retain the above copyright
|
||
|
// notice, this list of conditions and the following disclaimer.
|
||
|
// 2. Redistributions in binary form must reproduce the above copyright
|
||
|
// notice, this list of conditions and the following disclaimer in the
|
||
|
// documentation and/or other materials provided with the distribution.
|
||
|
// 3. The name of the author may not be used to endorse or promote products
|
||
|
// derived from this software without specific prior written permission.
|
||
|
//
|
||
|
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
|
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
|
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
|
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
|
// SUCH DAMAGE.
|
||
|
|
||
|
|
||
|
#include "XmlRpcCpp.h"
|
||
|
|
||
|
|
||
|
//=========================================================================
|
||
|
// XmlRpcFault Methods
|
||
|
//=========================================================================
|
||
|
|
||
|
XmlRpcFault::XmlRpcFault (const XmlRpcFault &fault) {
|
||
|
xmlrpc_env_init(&mFault);
|
||
|
xmlrpc_env_set_fault(&mFault,
|
||
|
fault.mFault.fault_code,
|
||
|
fault.mFault.fault_string);
|
||
|
}
|
||
|
|
||
|
XmlRpcFault::XmlRpcFault (const int faultCode, const string faultString) {
|
||
|
xmlrpc_env_init(&mFault);
|
||
|
xmlrpc_env_set_fault(&mFault, faultCode,
|
||
|
const_cast<char*>(faultString.c_str()));
|
||
|
}
|
||
|
|
||
|
XmlRpcFault::XmlRpcFault (const xmlrpc_env *env) {
|
||
|
if (!env->fault_string)
|
||
|
throw XmlRpcFault(XMLRPC_INTERNAL_ERROR,
|
||
|
"Tried to create empty fault");
|
||
|
xmlrpc_env_init(&mFault);
|
||
|
xmlrpc_env_set_fault(&mFault, env->fault_code,
|
||
|
const_cast<char*>(env->fault_string));
|
||
|
}
|
||
|
|
||
|
XmlRpcFault::~XmlRpcFault (void) {
|
||
|
xmlrpc_env_clean(&mFault);
|
||
|
}
|
||
|
|
||
|
string XmlRpcFault::getFaultString (void) const {
|
||
|
XMLRPC_ASSERT(mFault.fault_occurred);
|
||
|
return string(mFault.fault_string);
|
||
|
}
|
||
|
|
||
|
|
||
|
//=========================================================================
|
||
|
// XmlRpcEnv Methods
|
||
|
//=========================================================================
|
||
|
|
||
|
XmlRpcEnv::XmlRpcEnv (const XmlRpcEnv &env) {
|
||
|
xmlrpc_env_init(&mEnv);
|
||
|
if (env.hasFaultOccurred())
|
||
|
xmlrpc_env_set_fault(&mEnv,
|
||
|
env.mEnv.fault_code,
|
||
|
env.mEnv.fault_string);
|
||
|
}
|
||
|
|
||
|
XmlRpcFault XmlRpcEnv::getFault (void) const {
|
||
|
return XmlRpcFault(&mEnv);
|
||
|
}
|
||
|
|
||
|
void XmlRpcEnv::throwMe (void) const {
|
||
|
throw XmlRpcFault(&mEnv);
|
||
|
}
|
||
|
|
||
|
|
||
|
//=========================================================================
|
||
|
// XmlRpcValue Methods
|
||
|
//=========================================================================
|
||
|
|
||
|
// If the user doesn't tell us what kind of value to create, use
|
||
|
// a false boolean value as the default.
|
||
|
XmlRpcValue::XmlRpcValue (void) {
|
||
|
XmlRpcEnv env;
|
||
|
mValue = xmlrpc_build_value(env, "b", (xmlrpc_bool) 0);
|
||
|
env.throwIfFaultOccurred();
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::makeInt (const XmlRpcValue::int32 i) {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *value = xmlrpc_build_value(env, "i", i);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(value, CONSUME_REFERENCE);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::makeBool (const bool b) {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *value = xmlrpc_build_value(env, "b", (xmlrpc_bool) b);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(value, CONSUME_REFERENCE);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::makeDouble (const double d) {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *value = xmlrpc_build_value(env, "d", d);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(value, CONSUME_REFERENCE);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::makeDateTime (const string& dateTime) {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *value;
|
||
|
const char *data = dateTime.c_str(); // Make sure we're not using wchar_t.
|
||
|
value = xmlrpc_build_value(env, "8", data);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(value, CONSUME_REFERENCE);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::makeString (const string& str) {
|
||
|
XmlRpcEnv env;
|
||
|
const char *data = str.data(); // Make sure we're not using wchar_t.
|
||
|
size_t size = str.size();
|
||
|
xmlrpc_value *value = xmlrpc_build_value(env, "s#", data, size);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(value, CONSUME_REFERENCE);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::makeString (const char *const str) {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *value = xmlrpc_build_value(env, "s", str);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(value, CONSUME_REFERENCE);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::makeString (const char *const str, size_t len) {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *value = xmlrpc_build_value(env, "s#", str, len);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(value, CONSUME_REFERENCE);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::makeArray (void) {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *value = xmlrpc_build_value(env, "()");
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(value, CONSUME_REFERENCE);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::makeStruct (void) {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *value = xmlrpc_struct_new(env);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(value, CONSUME_REFERENCE);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::makeBase64 (const unsigned char *const data,
|
||
|
size_t len)
|
||
|
{
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *value = xmlrpc_build_value(env, "6", data, len);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(value, CONSUME_REFERENCE);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue::int32 XmlRpcValue::getInt (void) const {
|
||
|
XmlRpcEnv env;
|
||
|
XmlRpcValue::int32 result;
|
||
|
xmlrpc_parse_value(env, mValue, "i", &result);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool XmlRpcValue::getBool (void) const {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_bool result;
|
||
|
xmlrpc_parse_value(env, mValue, "b", &result);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
double XmlRpcValue::getDouble (void) const {
|
||
|
XmlRpcEnv env;
|
||
|
double result;
|
||
|
xmlrpc_parse_value(env, mValue, "d", &result);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
string XmlRpcValue::getRawDateTime (void) const {
|
||
|
XmlRpcEnv env;
|
||
|
char *result;
|
||
|
xmlrpc_parse_value(env, mValue, "8", &result);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return string(result);
|
||
|
}
|
||
|
|
||
|
string XmlRpcValue::getString (void) const {
|
||
|
XmlRpcEnv env;
|
||
|
char *result;
|
||
|
size_t result_len;
|
||
|
xmlrpc_parse_value(env, mValue, "s#", &result, &result_len);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return string(result, result_len);
|
||
|
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::getArray (void) const {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *result;
|
||
|
xmlrpc_parse_value(env, mValue, "A", &result);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(result);
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::getStruct (void) const {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *result;
|
||
|
xmlrpc_parse_value(env, mValue, "S", &result);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(result);
|
||
|
}
|
||
|
|
||
|
void XmlRpcValue::getBase64 (const unsigned char *& out_data,
|
||
|
size_t& out_len) const
|
||
|
{
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_parse_value(env, mValue, "6", &out_data, &out_len);
|
||
|
env.throwIfFaultOccurred();
|
||
|
}
|
||
|
|
||
|
size_t XmlRpcValue::arraySize (void) const {
|
||
|
XmlRpcEnv env;
|
||
|
size_t result = xmlrpc_array_size(env, mValue);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void XmlRpcValue::arrayAppendItem (const XmlRpcValue& value) {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_array_append_item(env, mValue, value.borrowReference());
|
||
|
env.throwIfFaultOccurred();
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::arrayGetItem (int index) const {
|
||
|
XmlRpcEnv env;
|
||
|
xmlrpc_value *result = xmlrpc_array_get_item(env, mValue, index);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(result);
|
||
|
}
|
||
|
|
||
|
size_t XmlRpcValue::structSize (void) const {
|
||
|
XmlRpcEnv env;
|
||
|
size_t result = xmlrpc_struct_size(env, mValue);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool XmlRpcValue::structHasKey (const string& key) const {
|
||
|
XmlRpcEnv env;
|
||
|
const char *keystr = key.data();
|
||
|
size_t keylen = key.size();
|
||
|
bool result = xmlrpc_struct_has_key_n(env, mValue,
|
||
|
const_cast<char*>(keystr), keylen);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
XmlRpcValue XmlRpcValue::structGetValue (const string& key) const {
|
||
|
XmlRpcEnv env;
|
||
|
const char *keystr = key.data();
|
||
|
size_t keylen = key.size();
|
||
|
xmlrpc_value *result =
|
||
|
xmlrpc_struct_get_value_n(env, mValue,
|
||
|
const_cast<char*>(keystr), keylen);
|
||
|
env.throwIfFaultOccurred();
|
||
|
return XmlRpcValue(result);
|
||
|
}
|
||
|
|
||
|
void XmlRpcValue::structSetValue (const string& key, const XmlRpcValue& value)
|
||
|
{
|
||
|
XmlRpcEnv env;
|
||
|
const char *keystr = key.data();
|
||
|
size_t keylen = key.size();
|
||
|
xmlrpc_struct_set_value_n(env, mValue, (char*) keystr, keylen,
|
||
|
value.borrowReference());
|
||
|
env.throwIfFaultOccurred();
|
||
|
}
|
||
|
|
||
|
void XmlRpcValue::structGetKeyAndValue (const int index,
|
||
|
string& out_key,
|
||
|
XmlRpcValue& out_value) const
|
||
|
{
|
||
|
XmlRpcEnv env;
|
||
|
|
||
|
xmlrpc_value *key, *value;
|
||
|
xmlrpc_struct_get_key_and_value(env, mValue, index, &key, &value);
|
||
|
env.throwIfFaultOccurred();
|
||
|
|
||
|
out_key = XmlRpcValue(key).getString();
|
||
|
out_value = XmlRpcValue(value);
|
||
|
}
|
||
|
|
||
|
XmlRpcGenSrv& XmlRpcGenSrv::addMethod (const string& name,
|
||
|
xmlrpc_method method,
|
||
|
void *data)
|
||
|
{
|
||
|
XmlRpcEnv env;
|
||
|
|
||
|
xmlrpc_registry_add_method (env, mRegistry, NULL,
|
||
|
name.c_str (),
|
||
|
method, data);
|
||
|
|
||
|
env.throwIfFaultOccurred ();
|
||
|
return (*this);
|
||
|
}
|
||
|
|
||
|
XmlRpcGenSrv& XmlRpcGenSrv::addMethod (const string& name,
|
||
|
xmlrpc_method method,
|
||
|
void* data,
|
||
|
const string& signature,
|
||
|
const string& help)
|
||
|
{
|
||
|
XmlRpcEnv env;
|
||
|
|
||
|
xmlrpc_registry_add_method_w_doc (env, mRegistry, NULL,
|
||
|
name.c_str (),
|
||
|
method, data,
|
||
|
signature.c_str (),
|
||
|
help.c_str ());
|
||
|
|
||
|
env.throwIfFaultOccurred ();
|
||
|
return (*this);
|
||
|
}
|
||
|
|
||
|
xmlrpc_mem_block* XmlRpcGenSrv::alloc (XmlRpcEnv& env, const string& body) const
|
||
|
{
|
||
|
xmlrpc_mem_block* result = NULL;
|
||
|
char* contents;
|
||
|
|
||
|
result = xmlrpc_mem_block_new (env, body.length ());
|
||
|
env.throwIfFaultOccurred ();
|
||
|
|
||
|
contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, result);
|
||
|
|
||
|
memcpy (contents, body.c_str (), body.length ());
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
string XmlRpcGenSrv::handle (const string& body) const
|
||
|
{
|
||
|
XmlRpcEnv env;
|
||
|
string result;
|
||
|
xmlrpc_mem_block* input = NULL, * output = NULL;
|
||
|
char* input_data, * output_data;
|
||
|
size_t input_size, output_size;
|
||
|
|
||
|
if (body.length () > xmlrpc_limit_get (XMLRPC_XML_SIZE_LIMIT_ID))
|
||
|
throw XmlRpcFault (XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC request too large");
|
||
|
|
||
|
input = alloc (env, body);
|
||
|
input_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, input);
|
||
|
input_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, input);
|
||
|
|
||
|
output = xmlrpc_registry_process_call (env, mRegistry, NULL,
|
||
|
input_data, input_size);
|
||
|
|
||
|
if (output)
|
||
|
{
|
||
|
output_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output);
|
||
|
output_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output);
|
||
|
|
||
|
result.assign (output_data, output_size);
|
||
|
xmlrpc_mem_block_free (output);
|
||
|
}
|
||
|
|
||
|
xmlrpc_mem_block_free (input);
|
||
|
if (!result.length ())
|
||
|
throw XmlRpcFault (env);
|
||
|
|
||
|
return result;
|
||
|
}
|