#include <XmlRpcServerConnection.h>
Inheritance diagram for XmlRpc::XmlRpcServerConnection:
Public Member Functions | |
virtual void | close () |
Close the owned fd. If deleteOnClose was specified at construction, the object is deleted. | |
int | getfd () const |
Return the file descriptor being monitored. | |
bool | getKeepOpen () const |
Return whether the file descriptor should be kept open if it is no longer monitored. | |
virtual unsigned | handleEvent (unsigned eventType) |
void | setfd (int fd) |
Specify the file descriptor to monitor. | |
void | setKeepOpen (bool b=true) |
Specify whether the file descriptor should be kept open if it is no longer monitored. | |
XmlRpcServerConnection (int fd, XmlRpcServer *server, bool deleteOnClose=false) | |
Constructor. | |
virtual | ~XmlRpcServerConnection () |
Destructor. | |
Static Public Attributes | |
const std::string | FAULTCODE = "faultCode" |
const std::string | FAULTSTRING = "faultString" |
const std::string | METHODNAME = "methodName" |
const char | METHODNAME_TAG [] = "<methodName>" |
const char | PARAM_ETAG [] = "</param>" |
const char | PARAM_TAG [] = "<param>" |
const std::string | PARAMS = "params" |
const char | PARAMS_ETAG [] = "</params>" |
const char | PARAMS_TAG [] = "<params>" |
const std::string | SYSTEM_MULTICALL = "system.multicall" |
Protected Types | |
enum | ServerConnectionState { READ_HEADER, READ_REQUEST, WRITE_RESPONSE } |
Protected Member Functions | |
bool | executeMethod (const std::string &methodName, XmlRpcValue ¶ms, XmlRpcValue &result) |
bool | executeMulticall (const std::string &methodName, XmlRpcValue ¶ms, XmlRpcValue &result) |
virtual void | executeRequest () |
void | generateFaultResponse (std::string const &msg, int errorCode=-1) |
std::string | generateHeader (std::string const &body) |
void | generateResponse (std::string const &resultXml) |
std::string | parseRequest (XmlRpcValue ¶ms) |
bool | readHeader () |
bool | readRequest () |
bool | writeResponse () |
Protected Attributes | |
int | _bytesWritten |
ServerConnectionState | _connectionState |
int | _contentLength |
std::string | _header |
bool | _keepAlive |
std::string | _request |
std::string | _response |
XmlRpcServer * | _server |
|
00079 { READ_HEADER, READ_REQUEST, WRITE_RESPONSE };
|
|
Constructor.
00030 : 00031 XmlRpcSource(fd, deleteOnClose) 00032 { 00033 XmlRpcUtil::log(2,"XmlRpcServerConnection: new socket %d.", fd); 00034 _server = server; 00035 _connectionState = READ_HEADER; 00036 _keepAlive = true; 00037 }
|
|
Destructor.
00041 { 00042 XmlRpcUtil::log(4,"XmlRpcServerConnection dtor."); 00043 _server->removeConnection(this); 00044 }
|
|
Close the owned fd. If deleteOnClose was specified at construction, the object is deleted.
Reimplemented in XmlRpc::XmlRpcClient. 00021 { 00022 if (_fd != -1) { 00023 XmlRpcUtil::log(2,"XmlRpcSource::close: closing socket %d.", _fd); 00024 XmlRpcSocket::close(_fd); 00025 XmlRpcUtil::log(2,"XmlRpcSource::close: done closing socket %d.", _fd); 00026 _fd = -1; 00027 } 00028 if (_deleteOnClose) { 00029 XmlRpcUtil::log(2,"XmlRpcSource::close: deleting this"); 00030 _deleteOnClose = false; 00031 delete this; 00032 } 00033 }
|
|
00255 { 00256 XmlRpcServerMethod* method = _server->findMethod(methodName); 00257 00258 if ( ! method) return false; 00259 00260 method->execute(params, result); 00261 00262 // Ensure a valid result value 00263 if ( ! result.valid()) 00264 result = std::string(); 00265 00266 return true; 00267 }
|
|
00273 { 00274 if (methodName != SYSTEM_MULTICALL) return false; 00275 00276 // There ought to be 1 parameter, an array of structs 00277 if (params.size() != 1 || params[0].getType() != XmlRpcValue::TypeArray) 00278 throw XmlRpcException(SYSTEM_MULTICALL + ": Invalid argument (expected an array)"); 00279 00280 int nc = params[0].size(); 00281 result.setSize(nc); 00282 00283 for (int i=0; i<nc; ++i) { 00284 00285 if ( ! params[0][i].hasMember(METHODNAME) || 00286 ! params[0][i].hasMember(PARAMS)) { 00287 result[i][FAULTCODE] = -1; 00288 result[i][FAULTSTRING] = SYSTEM_MULTICALL + 00289 ": Invalid argument (expected a struct with members methodName and params)"; 00290 continue; 00291 } 00292 00293 const std::string& methodName = params[0][i][METHODNAME]; 00294 XmlRpcValue& methodParams = params[0][i][PARAMS]; 00295 00296 XmlRpcValue resultValue; 00297 resultValue.setSize(1); 00298 try { 00299 if ( ! executeMethod(methodName, methodParams, resultValue[0]) && 00300 ! executeMulticall(methodName, params, resultValue[0])) 00301 { 00302 result[i][FAULTCODE] = -1; 00303 result[i][FAULTSTRING] = methodName + ": unknown method name"; 00304 } 00305 else 00306 result[i] = resultValue; 00307 00308 } catch (const XmlRpcException& fault) { 00309 result[i][FAULTCODE] = fault.getCode(); 00310 result[i][FAULTSTRING] = fault.getMessage(); 00311 } 00312 } 00313 00314 return true; 00315 }
|
|
00208 { 00209 XmlRpcValue params, resultValue; 00210 std::string methodName = parseRequest(params); 00211 XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: server calling method '%s'", 00212 methodName.c_str()); 00213 00214 try { 00215 00216 if ( ! executeMethod(methodName, params, resultValue) && 00217 ! executeMulticall(methodName, params, resultValue)) 00218 generateFaultResponse(methodName + ": unknown method name"); 00219 else 00220 generateResponse(resultValue.toXml()); 00221 00222 } catch (const XmlRpcException& fault) { 00223 XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: fault %s.", 00224 fault.getMessage().c_str()); 00225 generateFaultResponse(fault.getMessage(), fault.getCode()); 00226 } 00227 }
|
|
00356 { 00357 const char RESPONSE_1[] = 00358 "<?xml version=\"1.0\"?>\r\n" 00359 "<methodResponse><fault>\r\n\t"; 00360 const char RESPONSE_2[] = 00361 "\r\n</fault></methodResponse>\r\n"; 00362 00363 XmlRpcValue faultStruct; 00364 faultStruct[FAULTCODE] = errorCode; 00365 faultStruct[FAULTSTRING] = errorMsg; 00366 std::string body = RESPONSE_1 + faultStruct.toXml() + RESPONSE_2; 00367 std::string header = generateHeader(body); 00368 00369 _response = header + body; 00370 }
|
|
00338 { 00339 std::string header = 00340 "HTTP/1.1 200 OK\r\n" 00341 "Server: "; 00342 header += XMLRPC_VERSION; 00343 header += "\r\n" 00344 "Content-Type: text/xml\r\n" 00345 "Content-length: "; 00346 00347 char buffLen[40]; 00348 sprintf(buffLen,"%d\r\n\r\n", body.size()); 00349 00350 return header + buffLen; 00351 }
|
|
00321 { 00322 const char RESPONSE_1[] = 00323 "<?xml version=\"1.0\"?>\r\n" 00324 "<methodResponse><params><param>\r\n\t"; 00325 const char RESPONSE_2[] = 00326 "\r\n</param></params></methodResponse>\r\n"; 00327 00328 std::string body = RESPONSE_1 + resultXml + RESPONSE_2; 00329 std::string header = generateHeader(body); 00330 00331 _response = header + body; 00332 XmlRpcUtil::log(5, "XmlRpcServerConnection::generateResponse:\n%s\n", _response.c_str()); 00333 }
|
|
Return the file descriptor being monitored.
00025 { return _fd; }
|
|
Return whether the file descriptor should be kept open if it is no longer monitored.
00030 { return _keepOpen; }
|
|
Handle IO on the client connection socket.
Implements XmlRpc::XmlRpcSource. 00052 { 00053 if (_connectionState == READ_HEADER) 00054 if ( ! readHeader()) return 0; 00055 00056 if (_connectionState == READ_REQUEST) 00057 if ( ! readRequest()) return 0; 00058 00059 if (_connectionState == WRITE_RESPONSE) 00060 if ( ! writeResponse()) return 0; 00061 00062 return (_connectionState == WRITE_RESPONSE) 00063 ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent; 00064 }
|
|
00232 { 00233 int offset = 0; // Number of chars parsed from the request 00234 00235 std::string methodName = XmlRpcUtil::parseTag(METHODNAME_TAG, _request, &offset); 00236 00237 if (methodName.size() > 0 && XmlRpcUtil::findTag(PARAMS_TAG, _request, &offset)) 00238 { 00239 int nArgs = 0; 00240 while (XmlRpcUtil::nextTagIs(PARAM_TAG, _request, &offset)) { 00241 params[nArgs++] = XmlRpcValue(_request, &offset); 00242 (void) XmlRpcUtil::nextTagIs(PARAM_ETAG, _request, &offset); 00243 } 00244 00245 (void) XmlRpcUtil::nextTagIs(PARAMS_ETAG, _request, &offset); 00246 } 00247 00248 return methodName; 00249 }
|
|
00069 { 00070 // Read available data 00071 bool eof; 00072 if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof)) { 00073 // Its only an error if we already have read some data 00074 if (_header.length() > 0) 00075 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error while reading header (%s).",XmlRpcSocket::getErrorMsg().c_str()); 00076 return false; 00077 } 00078 00079 XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length()); 00080 char *hp = (char*)_header.c_str(); // Start of header 00081 char *ep = hp + _header.length(); // End of string 00082 char *bp = 0; // Start of body 00083 char *lp = 0; // Start of content-length value 00084 char *kp = 0; // Start of connection value 00085 00086 for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) { 00087 if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0)) 00088 lp = cp + 16; 00089 else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0)) 00090 kp = cp + 12; 00091 else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0)) 00092 bp = cp + 4; 00093 else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0)) 00094 bp = cp + 2; 00095 } 00096 00097 // If we haven't gotten the entire header yet, return (keep reading) 00098 if (bp == 0) { 00099 // EOF in the middle of a request is an error, otherwise its ok 00100 if (eof) { 00101 XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF"); 00102 if (_header.length() > 0) 00103 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header"); 00104 return false; // Either way we close the connection 00105 } 00106 00107 return true; // Keep reading 00108 } 00109 00110 // Decode content length 00111 if (lp == 0) { 00112 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified"); 00113 return false; // We could try to figure it out by parsing as we read, but for now... 00114 } 00115 00116 _contentLength = atoi(lp); 00117 if (_contentLength <= 0) { 00118 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength); 00119 return false; 00120 } 00121 00122 XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength); 00123 00124 // Otherwise copy non-header data to request buffer and set state to read request. 00125 _request = bp; 00126 00127 // Parse out any interesting bits from the header (HTTP version, connection) 00128 _keepAlive = true; 00129 if (_header.find("HTTP/1.0") != std::string::npos) { 00130 if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0) 00131 _keepAlive = false; // Default for HTTP 1.0 is to close the connection 00132 } else { 00133 if (kp != 0 && strncasecmp(kp, "close", 5) == 0) 00134 _keepAlive = false; 00135 } 00136 XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive); 00137 00138 00139 _header = ""; 00140 _connectionState = READ_REQUEST; 00141 return true; // Continue monitoring this source 00142 }
|
|
00146 { 00147 // If we dont have the entire request yet, read available data 00148 if (int(_request.length()) < _contentLength) { 00149 bool eof; 00150 if ( ! XmlRpcSocket::nbRead(this->getfd(), _request, &eof)) { 00151 XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error (%s).",XmlRpcSocket::getErrorMsg().c_str()); 00152 return false; 00153 } 00154 00155 // If we haven't gotten the entire request yet, return (keep reading) 00156 if (int(_request.length()) < _contentLength) { 00157 if (eof) { 00158 XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request"); 00159 return false; // Either way we close the connection 00160 } 00161 return true; 00162 } 00163 } 00164 00165 // Otherwise, parse and dispatch the request 00166 XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length()); 00167 //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str()); 00168 00169 _connectionState = WRITE_RESPONSE; 00170 00171 return true; // Continue monitoring this source 00172 }
|
|
Specify the file descriptor to monitor.
00027 { _fd = fd; }
|
|
Specify whether the file descriptor should be kept open if it is no longer monitored.
00032 { _keepOpen = b; }
|
|
00177 { 00178 if (_response.length() == 0) { 00179 executeRequest(); 00180 _bytesWritten = 0; 00181 if (_response.length() == 0) { 00182 XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response."); 00183 return false; 00184 } 00185 } 00186 00187 // Try to write the response 00188 if ( ! XmlRpcSocket::nbWrite(this->getfd(), _response, &_bytesWritten)) { 00189 XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error (%s).",XmlRpcSocket::getErrorMsg().c_str()); 00190 return false; 00191 } 00192 XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length()); 00193 00194 // Prepare to read the next request 00195 if (_bytesWritten == int(_response.length())) { 00196 _header = ""; 00197 _request = ""; 00198 _response = ""; 00199 _connectionState = READ_HEADER; 00200 } 00201 00202 return _keepAlive; // Continue monitoring this source if true 00203 }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|