$search
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 // Static data 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 // The server delegates handling client requests to a serverConnection object. 00034 XmlRpcServerConnection::XmlRpcServerConnection(int fd, XmlRpcServer* server, bool deleteOnClose /*= false*/) : 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 // Handle input on the server socket by accepting the connection 00052 // and reading the rpc request. Return true to continue to monitor 00053 // the socket for events, false to remove it from the dispatcher. 00054 unsigned 00055 XmlRpcServerConnection::handleEvent(unsigned /*eventType*/) 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 // Read available data 00075 bool eof; 00076 if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof)) { 00077 // Its only an error if we already have read some data 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(); // Start of header 00085 char *ep = hp + _header.length(); // End of string 00086 char *bp = 0; // Start of body 00087 char *lp = 0; // Start of content-length value 00088 char *kp = 0; // Start of connection value 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 // If we haven't gotten the entire header yet, return (keep reading) 00102 if (bp == 0) { 00103 // EOF in the middle of a request is an error, otherwise its ok 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; // Either way we close the connection 00109 } 00110 00111 return true; // Keep reading 00112 } 00113 00114 // Decode content length 00115 if (lp == 0) { 00116 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified"); 00117 return false; // We could try to figure it out by parsing as we read, but for now... 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 // Otherwise copy non-header data to request buffer and set state to read request. 00129 _request = bp; 00130 00131 // Parse out any interesting bits from the header (HTTP version, connection) 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; // Default for HTTP 1.0 is to close the connection 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; // Continue monitoring this source 00146 } 00147 00148 bool 00149 XmlRpcServerConnection::readRequest() 00150 { 00151 // If we dont have the entire request yet, read available data 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 // If we haven't gotten the entire request yet, return (keep reading) 00160 if (int(_request.length()) < _contentLength) { 00161 if (eof) { 00162 XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request"); 00163 return false; // Either way we close the connection 00164 } 00165 return true; 00166 } 00167 } 00168 00169 // Otherwise, parse and dispatch the request 00170 XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length()); 00171 //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str()); 00172 00173 _connectionState = WRITE_RESPONSE; 00174 00175 return true; // Continue monitoring this source 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 // Try to write the response 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 // Prepare to read the next request 00199 if (_bytesWritten == int(_response.length())) { 00200 _header = ""; 00201 _request = ""; 00202 _response = ""; 00203 _connectionState = READ_HEADER; 00204 } 00205 00206 return _keepAlive; // Continue monitoring this source if true 00207 } 00208 00209 // Run the method, generate _response string 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 // Parse the method name and the argument values from the request. 00234 std::string 00235 XmlRpcServerConnection::parseRequest(XmlRpcValue& params) 00236 { 00237 int offset = 0; // Number of chars parsed from the request 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 // Execute a named method with the specified params. 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 // Ensure a valid result value 00267 if ( ! result.valid()) 00268 result = std::string(); 00269 00270 return true; 00271 } 00272 00273 // Execute multiple calls and return the results in an array. 00274 bool 00275 XmlRpcServerConnection::executeMulticall(const std::string& methodName, 00276 XmlRpcValue& params, XmlRpcValue& result) 00277 { 00278 if (methodName != SYSTEM_MULTICALL) return false; 00279 00280 // There ought to be 1 parameter, an array of structs 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 // Create a response from results xml 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 // Prepend http headers 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