00001
00002 #include "XmlRpcServerConnection.h"
00003
00004 #include "XmlRpcSocket.h"
00005 #include "XmlRpc.h"
00006 #ifndef MAKEDEPEND
00007 # include <stdio.h>
00008 # include <stdlib.h>
00009 #ifndef _WINDOWS
00010 # include <strings.h>
00011 #endif
00012 # include <string.h>
00013 #endif
00014
00015 using namespace XmlRpc;
00016
00017
00018 const char XmlRpcServerConnection::METHODNAME_TAG[] = "<methodName>";
00019 const char XmlRpcServerConnection::PARAMS_TAG[] = "<params>";
00020 const char XmlRpcServerConnection::PARAMS_ETAG[] = "</params>";
00021 const char XmlRpcServerConnection::PARAM_TAG[] = "<param>";
00022 const char XmlRpcServerConnection::PARAM_ETAG[] = "</param>";
00023
00024 const std::string XmlRpcServerConnection::SYSTEM_MULTICALL = "system.multicall";
00025 const std::string XmlRpcServerConnection::METHODNAME = "methodName";
00026 const std::string XmlRpcServerConnection::PARAMS = "params";
00027
00028 const std::string XmlRpcServerConnection::FAULTCODE = "faultCode";
00029 const std::string XmlRpcServerConnection::FAULTSTRING = "faultString";
00030
00031
00032
00033
00034 XmlRpcServerConnection::XmlRpcServerConnection(int fd, XmlRpcServer* server, bool deleteOnClose ) :
00035 XmlRpcSource(fd, deleteOnClose)
00036 {
00037 XmlRpcUtil::log(2,"XmlRpcServerConnection: new socket %d.", fd);
00038 _server = server;
00039 _connectionState = READ_HEADER;
00040 _contentLength = 0;
00041 _bytesWritten = 0;
00042 _keepAlive = true;
00043 }
00044
00045
00046 XmlRpcServerConnection::~XmlRpcServerConnection()
00047 {
00048 XmlRpcUtil::log(4,"XmlRpcServerConnection dtor.");
00049 _server->removeConnection(this);
00050 }
00051
00052
00053
00054
00055
00056 unsigned
00057 XmlRpcServerConnection::handleEvent(unsigned )
00058 {
00059 if (_connectionState == READ_HEADER)
00060 if ( ! readHeader()) return 0;
00061
00062 if (_connectionState == READ_REQUEST)
00063 if ( ! readRequest()) return 0;
00064
00065 if (_connectionState == WRITE_RESPONSE)
00066 if ( ! writeResponse()) return 0;
00067
00068 return (_connectionState == WRITE_RESPONSE)
00069 ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
00070 }
00071
00072
00073 bool
00074 XmlRpcServerConnection::readHeader()
00075 {
00076
00077 bool eof;
00078 if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof)) {
00079
00080 if (_header.length() > 0)
00081 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error while reading header (%s).",XmlRpcSocket::getErrorMsg().c_str());
00082 return false;
00083 }
00084
00085 XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length());
00086 char *hp = (char*)_header.c_str();
00087 char *ep = hp + _header.length();
00088 char *bp = 0;
00089 char *lp = 0;
00090 char *kp = 0;
00091
00092 for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
00093 if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
00094 lp = cp + 16;
00095 else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0))
00096 kp = cp + 12;
00097 else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
00098 bp = cp + 4;
00099 else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
00100 bp = cp + 2;
00101 }
00102
00103
00104 if (bp == 0) {
00105
00106 if (eof) {
00107 XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF");
00108 if (_header.length() > 0)
00109 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header");
00110 return false;
00111 }
00112
00113 return true;
00114 }
00115
00116
00117 if (lp == 0) {
00118 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified");
00119 return false;
00120 }
00121
00122 _contentLength = atoi(lp);
00123 if (_contentLength <= 0) {
00124 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength);
00125 return false;
00126 }
00127
00128 XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength);
00129
00130
00131 _request = bp;
00132
00133
00134 _keepAlive = true;
00135 if (_header.find("HTTP/1.0") != std::string::npos) {
00136 if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0)
00137 _keepAlive = false;
00138 } else {
00139 if (kp != 0 && strncasecmp(kp, "close", 5) == 0)
00140 _keepAlive = false;
00141 }
00142 XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive);
00143
00144
00145 _header = "";
00146 _connectionState = READ_REQUEST;
00147 return true;
00148 }
00149
00150 bool
00151 XmlRpcServerConnection::readRequest()
00152 {
00153
00154 if (int(_request.length()) < _contentLength) {
00155 bool eof;
00156 if ( ! XmlRpcSocket::nbRead(this->getfd(), _request, &eof)) {
00157 XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
00158 return false;
00159 }
00160
00161
00162 if (int(_request.length()) < _contentLength) {
00163 if (eof) {
00164 XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request");
00165 return false;
00166 }
00167 return true;
00168 }
00169 }
00170
00171
00172 XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length());
00173
00174
00175 _connectionState = WRITE_RESPONSE;
00176
00177 return true;
00178 }
00179
00180
00181 bool
00182 XmlRpcServerConnection::writeResponse()
00183 {
00184 if (_response.length() == 0) {
00185 executeRequest();
00186 _bytesWritten = 0;
00187 if (_response.length() == 0) {
00188 XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response.");
00189 return false;
00190 }
00191 }
00192
00193
00194 if ( ! XmlRpcSocket::nbWrite(this->getfd(), _response, &_bytesWritten)) {
00195 XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
00196 return false;
00197 }
00198 XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length());
00199
00200
00201 if (_bytesWritten == int(_response.length())) {
00202 _header = "";
00203 _request = "";
00204 _response = "";
00205 _connectionState = READ_HEADER;
00206 }
00207
00208 return _keepAlive;
00209 }
00210
00211
00212 void
00213 XmlRpcServerConnection::executeRequest()
00214 {
00215 XmlRpcValue params, resultValue;
00216 std::string methodName = parseRequest(params);
00217 XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: server calling method '%s'",
00218 methodName.c_str());
00219
00220 try {
00221
00222 if ( ! executeMethod(methodName, params, resultValue) &&
00223 ! executeMulticall(methodName, params, resultValue))
00224 generateFaultResponse(methodName + ": unknown method name");
00225 else
00226 generateResponse(resultValue.toXml());
00227
00228 } catch (const XmlRpcException& fault) {
00229 XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: fault %s.",
00230 fault.getMessage().c_str());
00231 generateFaultResponse(fault.getMessage(), fault.getCode());
00232 }
00233 }
00234
00235
00236 std::string
00237 XmlRpcServerConnection::parseRequest(XmlRpcValue& params)
00238 {
00239 int offset = 0;
00240
00241 std::string methodName = XmlRpcUtil::parseTag(METHODNAME_TAG, _request, &offset);
00242
00243 if (methodName.size() > 0 && XmlRpcUtil::findTag(PARAMS_TAG, _request, &offset))
00244 {
00245 int nArgs = 0;
00246 while (XmlRpcUtil::nextTagIs(PARAM_TAG, _request, &offset)) {
00247 params[nArgs++] = XmlRpcValue(_request, &offset);
00248 (void) XmlRpcUtil::nextTagIs(PARAM_ETAG, _request, &offset);
00249 }
00250
00251 (void) XmlRpcUtil::nextTagIs(PARAMS_ETAG, _request, &offset);
00252 }
00253
00254 return methodName;
00255 }
00256
00257
00258 bool
00259 XmlRpcServerConnection::executeMethod(const std::string& methodName,
00260 XmlRpcValue& params, XmlRpcValue& result)
00261 {
00262 XmlRpcServerMethod* method = _server->findMethod(methodName);
00263
00264 if ( ! method) return false;
00265
00266 method->execute(params, result);
00267
00268
00269 if ( ! result.valid())
00270 result = std::string();
00271
00272 return true;
00273 }
00274
00275
00276 bool
00277 XmlRpcServerConnection::executeMulticall(const std::string& methodName,
00278 XmlRpcValue& params, XmlRpcValue& result)
00279 {
00280 if (methodName != SYSTEM_MULTICALL) return false;
00281
00282
00283 if (params.size() != 1 || params[0].getType() != XmlRpcValue::TypeArray)
00284 throw XmlRpcException(SYSTEM_MULTICALL + ": Invalid argument (expected an array)");
00285
00286 int nc = params[0].size();
00287 result.setSize(nc);
00288
00289 for (int i=0; i<nc; ++i) {
00290
00291 if ( ! params[0][i].hasMember(METHODNAME) ||
00292 ! params[0][i].hasMember(PARAMS)) {
00293 result[i][FAULTCODE] = -1;
00294 result[i][FAULTSTRING] = SYSTEM_MULTICALL +
00295 ": Invalid argument (expected a struct with members methodName and params)";
00296 continue;
00297 }
00298
00299 const std::string& methodName = params[0][i][METHODNAME];
00300 XmlRpcValue& methodParams = params[0][i][PARAMS];
00301
00302 XmlRpcValue resultValue;
00303 resultValue.setSize(1);
00304 try {
00305 if ( ! executeMethod(methodName, methodParams, resultValue[0]) &&
00306 ! executeMulticall(methodName, params, resultValue[0]))
00307 {
00308 result[i][FAULTCODE] = -1;
00309 result[i][FAULTSTRING] = methodName + ": unknown method name";
00310 }
00311 else
00312 result[i] = resultValue;
00313
00314 } catch (const XmlRpcException& fault) {
00315 result[i][FAULTCODE] = fault.getCode();
00316 result[i][FAULTSTRING] = fault.getMessage();
00317 }
00318 }
00319
00320 return true;
00321 }
00322
00323
00324
00325 void
00326 XmlRpcServerConnection::generateResponse(std::string const& resultXml)
00327 {
00328 const char RESPONSE_1[] =
00329 "<?xml version=\"1.0\"?>\r\n"
00330 "<methodResponse><params><param>\r\n\t";
00331 const char RESPONSE_2[] =
00332 "\r\n</param></params></methodResponse>\r\n";
00333
00334 std::string body = RESPONSE_1 + resultXml + RESPONSE_2;
00335 std::string header = generateHeader(body);
00336
00337 _response = header + body;
00338 XmlRpcUtil::log(5, "XmlRpcServerConnection::generateResponse:\n%s\n", _response.c_str());
00339 }
00340
00341
00342 std::string
00343 XmlRpcServerConnection::generateHeader(std::string const& body)
00344 {
00345 std::string header =
00346 "HTTP/1.1 200 OK\r\n"
00347 "Server: ";
00348 header += XMLRPC_VERSION;
00349 header += "\r\n"
00350 "Content-Type: text/xml\r\n"
00351 "Content-length: ";
00352
00353 char buffLen[40];
00354 #ifdef _MSC_VER
00355 sprintf_s(buffLen,40,"%d\r\n\r\n", (int)body.size());
00356 #else
00357 sprintf(buffLen,"%d\r\n\r\n", (int)body.size());
00358 #endif
00359
00360 return header + buffLen;
00361 }
00362
00363
00364 void
00365 XmlRpcServerConnection::generateFaultResponse(std::string const& errorMsg, int errorCode)
00366 {
00367 const char RESPONSE_1[] =
00368 "<?xml version=\"1.0\"?>\r\n"
00369 "<methodResponse><fault>\r\n\t";
00370 const char RESPONSE_2[] =
00371 "\r\n</fault></methodResponse>\r\n";
00372
00373 XmlRpcValue faultStruct;
00374 faultStruct[FAULTCODE] = errorCode;
00375 faultStruct[FAULTSTRING] = errorMsg;
00376 std::string body = RESPONSE_1 + faultStruct.toXml() + RESPONSE_2;
00377 std::string header = generateHeader(body);
00378
00379 _response = header + body;
00380 }
00381