xmlrpc.cpp

Go to the documentation of this file.
00001 
00002  //
00003  // XMLStorage XML-RPC extension
00004  //
00005  // Copyright (c) 2009, 2014 Martin Fuchs <martin-fuchs@gmx.net>
00006  //
00007 
00008 
00009 /*
00010 
00011   All rights reserved.
00012 
00013   Redistribution and use in source and binary forms, with or without
00014   modification, are permitted provided that the following conditions are met:
00015 
00016   * Redistributions of source code must retain the above copyright
00017     notice, this list of conditions and the following disclaimer.
00018   * Redistributions in binary form must reproduce the above copyright
00019     notice, this list of conditions and the following disclaimer in
00020     the documentation and/or other materials provided with the
00021     distribution.
00022 
00023   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00027   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00029   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00030   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00031   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00032   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033   POSSIBILITY OF SUCH DAMAGE.
00034 
00035 */
00036 
00037 #include "httpclnt.h"
00038 
00039 #pragma warning(disable: 4355)
00040 
00041 #include <time.h>
00042 
00043 
00044 namespace XMLRPC {
00045 
00046 
00047 ISODate::ISODate()
00048 {
00049 #ifdef _WIN32
00050     SYSTEMTIME time;
00051 
00052     GetLocalTime(&time);
00053 
00054     _year = time.wYear;
00055     _month = time.wMonth;
00056     _day  = time.wDay;
00057 
00058     _hour = time.wHour;
00059     _minute = time.wMinute;
00060     _second = time.wSecond;
00061 #else
00062     time_t t;
00063     struct tm lc;
00064 
00065     time(&t);
00066     localtime_r(&t, &lc);
00067 
00068     _year = lc.tm_year + 1900;
00069     _month = lc.tm_mon + 1;
00070     _day = lc.tm_mday;
00071 
00072     _hour = lc.tm_hour;
00073     _minute = lc.tm_min;
00074     _second = lc.tm_sec;
00075 #endif
00076 }
00077 
00078 ISODate::ISODate(const char* str)
00079 {
00080     if (sscanf_s(str, "%04d%02d%02dT%02d:%02d:%02d", &_year, &_month, &_day, &_hour, &_minute, &_second) != 6)
00081         throw Exception("invalid date format");
00082 }
00083 
00084 string ISODate::str() const
00085 {
00086     char buffer[18];
00087 
00088     sprintf(buffer, "%04d%02d%02dT%02d:%02d:%02d", _year, _month, _day, _hour, _minute, _second);
00089 
00090     return buffer;
00091 }
00092 
00093 
00094 #ifdef _WIN32
00095 
00096 static ULARGE_INTEGER get_time_number(const ISODate& date)
00097 {
00098     SYSTEMTIME st = {0};
00099 
00100     st.wYear = date._year;
00101     st.wMonth = date._month;
00102     st.wDay = date._day;
00103     st.wHour = date._hour;
00104     st.wMinute = date._minute;
00105     st.wSecond = date._second;
00106 
00107     FILETIME ft;
00108     SystemTimeToFileTime(&st, &ft);
00109 
00110     ULARGE_INTEGER li;
00111 
00112     li.LowPart = ft.dwLowDateTime;
00113     li.HighPart = ft.dwHighDateTime;
00114 
00115     return li;
00116 }
00117 
00118 long ISODate::diff(const ISODate& other) const
00119 {
00120     ULARGE_INTEGER li1 = get_time_number(*this);
00121     ULARGE_INTEGER li2 = get_time_number(other);
00122 
00123     return long((li1.QuadPart - li2.QuadPart) / 10000000);
00124 }
00125 
00126 #else // _WIN32
00127 
00128 static time_t get_time_t(const ISODate& date)
00129 {
00130     struct tm t = {
00131         date._second,
00132         date._minute,
00133         date._hour,
00134         date._day,
00135         date._month - 1,
00136         date._year - 1900
00137     };
00138 
00139     return mktime(&t);
00140 }
00141 
00142 long ISODate::diff(const ISODate& other) const
00143 {
00144     time_t t1 = get_time_t(*this);
00145     time_t t2 = get_time_t(other);
00146 
00147     return (long) difftime(t1, t2);
00148 }
00149 
00150 #endif
00151 
00152 
00153 Binary::Binary(const void* buffer, size_t len)
00154  :  _buffer(malloc(len)),
00155     _len(len)
00156 {
00157     memcpy(_buffer, buffer, len);
00158 }
00159 
00160 Binary::Binary(const char* base64)
00161 {
00162     _buffer = base64_decode(base64, _len);
00163 }
00164 
00165 Binary::Binary(const Binary& other)
00166  :  _buffer(malloc(other._len)),
00167     _len(other._len)
00168 {
00169     memcpy(_buffer, other._buffer, other._len);
00170 }
00171 
00172 string Binary::str() const
00173 {
00174     char* s = base64_encode(_buffer, _len);
00175     string ret = s;
00176     free(s);
00177 
00178     return ret;
00179 }
00180 
00181 
00182 XMLRPCArray::XMLRPCArray(const_XMLPos pos)
00183 {
00184     if (pos.go_down("data")) {
00185         const XMLNode::Children& values = pos->get_children();
00186 
00187         for(XMLNode::Children::const_iterator it=values.begin(); it!=values.end(); ++it) {
00188             assert(**it=="value");
00189 
00190             string value = XMLRPCValue::get_any(*it);
00191 
00192             push_back(value);
00193         }
00194     }
00195 }
00196 
00197 
00198 XMLRPCStruct::XMLRPCStruct(const XMLNode& node)
00199 {
00200     const XMLNode::Children& members = node.get_children();
00201 
00202     for(XMLNode::Children::const_iterator it=members.begin(); it!=members.end(); ++it) {
00203         const XMLNode* pNode = *it;
00204         assert(*pNode=="member");
00205 
00206         string value;
00207 
00208         const_XMLPos pos(pNode);
00209         if (pos.go_down("value"))
00210             value = XMLRPCValue::get_any(pos);
00211 
00212         const string& name = pNode->get_sub_content("name");
00213 
00214         (*this)[name] = value;
00215     }
00216 }
00217 
00218 
00219 string XMLRPCWriter::flush()
00220 {
00221     if (_params)
00222         _writer.back(); // </params>
00223 
00224     _writer.back(); // </methodCall> bzw. </methodResponse>
00225 
00226     return _buffer.str();
00227 }
00228 
00229 void XMLRPCWriter::write_string_param(const string& value)
00230 {
00231     if (!_params++)
00232         _writer.create("params");
00233 
00234     _writer.create("param");
00235         _writer.create("value");
00236             _writer.set_content(value);
00237         _writer.back();
00238     _writer.back();
00239 }
00240 
00241 void XMLRPCWriter::write_param(const string& type, const string& value)
00242 {
00243     if (!_params++)
00244         _writer.create("params");
00245 
00246     _writer.create("param");
00247         _writer.create("value");
00248             _writer.create(type);
00249                 _writer.set_content(value);
00250             _writer.back();
00251         _writer.back();
00252     _writer.back();
00253 }
00254 
00255 void XMLRPCWriter::write_param(const XMLRPCArray& arr)
00256 {
00257     if (!_params++)
00258         _writer.create("params");
00259 
00260     _writer.create("param");
00261       _writer.create("value");
00262         _writer.create("array");
00263           _writer.create("data");
00264 
00265             for(XMLRPCArray::const_iterator it=arr.begin(); it!=arr.end(); ++it) {
00266               _writer.create("value");
00267                 _writer.set_content(*it);
00268               _writer.back();
00269             }
00270 
00271           _writer.back();
00272         _writer.back();
00273       _writer.back();
00274     _writer.back();
00275 }
00276 
00277 void XMLRPCWriter::write_param(const XMLRPCStruct& str)
00278 {
00279     if (!_params++)
00280         _writer.create("params");
00281 
00282     write_struct(str, "param");
00283 }
00284 
00285  // The function write_struct() is used both when transmitting <struct> parameters and
00286  // when creating <fault> responses.
00287 void XMLRPCWriter::write_struct(const XMLRPCStruct& str, const string& keyword)
00288 {
00289     _writer.create(keyword);
00290       _writer.create("value");
00291         _writer.create("struct");
00292 
00293           for(XMLRPCStruct::const_iterator it=str.begin(); it!=str.end(); ++it) {
00294             _writer.create("member");
00295               _writer.create("name");
00296                 _writer.set_content(it->first);
00297               _writer.back();
00298 
00299               _writer.create("value");
00300                 _writer.set_content(it->second);
00301               _writer.back();
00302             _writer.back();
00303           }
00304 
00305         _writer.back();
00306       _writer.back();
00307     _writer.back();
00308 }
00309 
00310 
00311 XMLRPCParser::XMLRPCParser(const string& xml_str, const string& keyword)
00312  :  _pos(&_doc),
00313     _value_cnt(0)
00314 {
00315     if (_doc.read_buffer(xml_str))
00316         _pos.go_down(keyword);
00317 }
00318 
00319 bool XMLRPCParser::next_parameter()
00320 {
00321     if (!_pos.iterate("param", _value_cnt))
00322         return false;
00323 
00324     return _pos.go_down("value");
00325 }
00326 
00327 bool XMLRPCParser::more_parameters() const
00328 {
00329     XPath xpath;
00330     xpath.push_back(XPathElement("param", _value_cnt));
00331 
00332     return _pos->find_relative(xpath) != NULL;
00333 }
00334 
00335 XMLRPC_TYPE XMLRPCParser::get_next_type() const
00336 {
00337     XPath xpath;
00338     xpath.push_back(XPathElement("param", _value_cnt));
00339 
00340     const XMLNode* pNode = _pos->find_relative(xpath);
00341     if (!pNode)
00342         return XRT_VOID;
00343 
00344     return get_param_type(pNode);
00345 }
00346 
00347 XMLRPC_TYPE XMLRPCParser::get_param_type(const XMLNode* pNode)
00348 {
00349     pNode = pNode->find_relative("value");
00350     if (!pNode)
00351         return XRT_VOID;
00352 
00353     pNode = pNode->get_first_child();
00354     if (!pNode)
00355         return XRT_STRING;
00356 
00357     const XS_String& tag = *pNode;
00358 
00359     if (tag=="i4" || tag=="int")
00360         return XRT_INT;
00361     else if (tag == "double")
00362         return XRT_DOUBLE;
00363     else if (tag == "boolean")
00364         return XRT_BOOLEAN;
00365     else if (tag == "string")
00366         return XRT_STRING;
00367     else if (tag == "dateTime.iso8601")
00368         return XRT_DATE;
00369     else if (tag == "base64")
00370         return XRT_BINARY;
00371     else if (tag == "array")
00372         return XRT_ARRAY;
00373     else if (tag == "struct")
00374         return XRT_STRUCT;
00375     else
00376         return XRT_VOID;
00377 }
00378 
00379 size_t XMLRPCParser::get_parameter_types(TypeList& types) const
00380 {
00381     int n = 0;
00382 
00383     XMLPos pos = _pos;
00384 
00385     while(pos.iterate("param", n)) {
00386         types.push_back(get_param_type(pos));
00387 
00388         pos.back();
00389     }
00390 
00391     return n;
00392 }
00393 
00394 
00395 string XMLRPCParser::get_any()
00396 {
00397     if (next_parameter()) {
00398         const string& ret = XMLRPCValue::get_any(_pos);
00399 
00400         _pos.back(); // </value>
00401         _pos.back(); // </param>
00402 
00403         return ret;
00404     } else
00405         throw Exception("missing parameter value");
00406 }
00407 
00408 int XMLRPCParser::get_int()
00409 {
00410     if (next_parameter()) {
00411         int ret = XMLRPCValue::get_int(_pos);
00412 
00413         _pos.back(); // </value>
00414         _pos.back(); // </param>
00415 
00416         return ret;
00417     } else
00418         throw Exception("missing parameter value");
00419 }
00420 
00421 double XMLRPCParser::get_double()
00422 {
00423     if (next_parameter()) {
00424         double ret = XMLRPCValue::get_double(_pos);
00425 
00426         _pos.back();
00427         _pos.back();
00428 
00429         return ret;
00430     } else
00431         throw Exception("missing parameter value");
00432 }
00433 
00434 bool XMLRPCParser::get_bool()
00435 {
00436     if (next_parameter()) {
00437         bool ret = XMLRPCValue::get_bool(_pos);
00438 
00439         _pos.back();
00440         _pos.back();
00441 
00442         return ret;
00443     } else
00444         throw Exception("missing parameter value");
00445 }
00446 
00447 string XMLRPCParser::get_string()
00448 {
00449     if (next_parameter()) {
00450         string ret = XMLRPCValue::get_string(_pos);
00451 
00452         _pos.back();
00453         _pos.back();
00454 
00455         return ret;
00456     } else
00457         throw Exception("missing parameter value");
00458 }
00459 
00460 ISODate XMLRPCParser::get_date()
00461 {
00462     if (next_parameter()) {
00463         ISODate ret = XMLRPCValue::get_date(_pos);
00464 
00465         _pos.back();
00466         _pos.back();
00467 
00468         return ret;
00469     } else
00470         throw Exception("missing parameter value");
00471 }
00472 
00473 Binary XMLRPCParser::get_binary()
00474 {
00475     if (next_parameter()) {
00476         Binary ret = XMLRPCValue::get_binary(_pos);
00477 
00478         _pos.back();
00479         _pos.back();
00480 
00481         return ret; //TODO sub-optimal: invokes the copy constructor
00482     } else
00483         throw Exception("missing parameter value");
00484 }
00485 
00486 XMLRPCArray XMLRPCParser::get_array()
00487 {
00488     if (next_parameter()) {
00489         XMLRPCArray ret = XMLRPCValue::get_array(_pos);
00490 
00491         _pos.back();
00492         _pos.back();
00493 
00494         return ret;
00495     } else
00496         throw Exception("missing parameter value");
00497 }
00498 
00499 XMLRPCStruct XMLRPCParser::get_struct()
00500 {
00501     if (next_parameter()) {
00502         XMLRPCStruct ret = XMLRPCValue::get_struct(_pos);
00503 
00504         _pos.back();
00505         _pos.back();
00506 
00507         return ret;
00508     } else
00509         throw Exception("missing parameter value");
00510 }
00511 
00512 
00513 string XMLRPCValue::get_any(const_XMLPos pos)
00514 {
00515     pos.go_down();  // go to content node or skip for immediate string values
00516 
00517     return pos->get_content();
00518 }
00519 
00520 int XMLRPCValue::get_int(const_XMLPos pos)
00521 {
00522     if (pos.go_down("i4") || pos.go_down("int"))
00523         return XMLInt(pos->get_content());
00524     else
00525         throw Exception("wrong data type");
00526 }
00527 
00528 double XMLRPCValue::get_double(const_XMLPos pos)
00529 {
00530     if (pos.go_down("double"))
00531         return XMLDouble(pos->get_content());
00532     else
00533         throw Exception("wrong data type");
00534 }
00535 
00536 bool XMLRPCValue::get_bool(const_XMLPos pos)
00537 {
00538     if (pos.go_down("boolean"))
00539         return XMLInt(pos->get_content()) == 1;
00540     else
00541         throw Exception("wrong data type");
00542 }
00543 
00544 string XMLRPCValue::get_string(const_XMLPos pos)
00545 {
00546     if (pos.go_down("string"))
00547         return pos->get_content();
00548     else if (pos->get_children().empty())
00549         return pos->get_content();
00550     else
00551         throw Exception("wrong data type");
00552 }
00553 
00554 ISODate XMLRPCValue::get_date(const_XMLPos pos)
00555 {
00556     if (pos.go_down("dateTime.iso8601"))
00557         return ISODate(pos->get_content());
00558     else
00559         throw Exception("wrong data type");
00560 }
00561 
00562 Binary XMLRPCValue::get_binary(const_XMLPos pos)
00563 {
00564     if (pos.go_down("base64"))
00565         return Binary(pos->get_content());
00566     else
00567         throw Exception("wrong data type");
00568 }
00569 
00570 XMLRPCArray XMLRPCValue::get_array(const_XMLPos pos)
00571 {
00572     if (pos.go_down("array"))
00573         return XMLRPCArray(pos);
00574     else
00575         throw Exception("wrong data type");
00576 }
00577 
00578 XMLRPCStruct XMLRPCValue::get_struct(const_XMLPos pos)
00579 {
00580     if (pos.go_down("struct"))
00581         return XMLRPCStruct(*pos);
00582     else
00583         throw Exception("wrong data type");
00584 }
00585 
00586 
00587 } // namespace XMLRPC