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