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