XmlRpc::XmlRpcServerConnection Class Reference

#include <XmlRpcServerConnection.h>

Inheritance diagram for XmlRpc::XmlRpcServerConnection:

XmlRpc::XmlRpcSource List of all members.

Detailed Description

A class to handle XML RPC requests from a particular client.


Public Member Functions

 XmlRpcServerConnection (int fd, XmlRpcServer *server, bool deleteOnClose=false)
 Constructor.
virtual ~XmlRpcServerConnection ()
 Destructor.
virtual unsigned handleEvent (unsigned eventType)
 Handle IO on the client connection socket.

Protected Types

enum  ServerConnectionState { READ_HEADER, READ_REQUEST, WRITE_RESPONSE }
 Possible IO states for the connection. More...

Protected Member Functions

bool readHeader ()
 Reads the http header.
bool readRequest ()
 Reads the request (based on the content-length header value).
bool writeResponse ()
 Executes the request and writes the resulting response.
virtual void executeRequest ()
 Helper method to execute the client request.

Protected Attributes

XmlRpcServer_server
 The XmlRpc server that accepted this connection.
ServerConnectionState _connectionState
 Current IO state for the connection.
std::string _header
 Request headers.
int _contentLength
 Number of bytes expected in the request body (parsed from header).
std::string _request
 Request body.
std::string _response
 Response.
int _bytesWritten
 Number of bytes of the response written so far.
bool _keepAlive
 Whether to keep the current client connection open for further requests.


Member Enumeration Documentation

enum XmlRpc::XmlRpcServerConnection::ServerConnectionState [protected]

Possible IO states for the connection.

Enumerator:
READ_HEADER 
READ_REQUEST 
WRITE_RESPONSE 


Constructor & Destructor Documentation

XmlRpcServerConnection::XmlRpcServerConnection ( int  fd,
XmlRpcServer server,
bool  deleteOnClose = false 
)

Constructor.

00021                                                                                :
00022   XmlRpcSource(fd, deleteOnClose)
00023 {
00024   XmlRpcUtil::log(2,"XmlRpcServerConnection: new socket %d.", fd);
00025   _server = server;
00026   _connectionState = READ_HEADER;
00027   _keepAlive = true;
00028 }

XmlRpcServerConnection::~XmlRpcServerConnection (  )  [virtual]

Destructor.

00032 {
00033   XmlRpcUtil::log(4,"XmlRpcServerConnection dtor.");
00034   _server->removeConnection(this);
00035 }


Member Function Documentation

unsigned XmlRpcServerConnection::handleEvent ( unsigned  eventType  )  [virtual]

Handle IO on the client connection socket.

Parameters:
eventType Type of IO event that occurred.
See also:
XmlRpcDispatch::EventType.

Implements XmlRpc::XmlRpcSource.

00043 {
00044   if (_connectionState == READ_HEADER)
00045     if ( ! readHeader()) return 0;
00046 
00047   if (_connectionState == READ_REQUEST)
00048     if ( ! readRequest()) return 0;
00049 
00050   if (_connectionState == WRITE_RESPONSE)
00051     if ( ! writeResponse()) return 0;
00052 
00053   return (_connectionState == WRITE_RESPONSE) 
00054         ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
00055 }

bool XmlRpcServerConnection::readHeader (  )  [protected]

Reads the http header.

00060 {
00061   // Read available data
00062   bool eof;
00063   if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof, _ssl_ssl)) {
00064     // Its only an error if we already have read some data
00065     if (_header.length() > 0)
00066       XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error while reading header (%s).",XmlRpcSocket::getErrorMsg().c_str());
00067     return false;
00068   }
00069 
00070   XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length());
00071   char *hp = (char*)_header.c_str();  // Start of header
00072   char *ep = hp + _header.length();   // End of string
00073   char *bp = 0;                       // Start of body
00074   char *lp = 0;                       // Start of content-length value
00075   char *kp = 0;                       // Start of connection value
00076 
00077   for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
00078         if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
00079           lp = cp + 16;
00080         else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0))
00081           kp = cp + 12;
00082         else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
00083           bp = cp + 4;
00084         else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
00085           bp = cp + 2;
00086   }
00087 
00088   // If we haven't gotten the entire header yet, return (keep reading)
00089   if (bp == 0) {
00090     // EOF in the middle of a request is an error, otherwise its ok
00091     if (eof) {
00092       XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF");
00093       if (_header.length() > 0)
00094         XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header");
00095       return false;   // Either way we close the connection
00096     }
00097     
00098     return true;  // Keep reading
00099   }
00100 
00101   // Decode content length
00102   if (lp == 0) {
00103     XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified");
00104     return false;   // We could try to figure it out by parsing as we read, but for now...
00105   }
00106 
00107   _contentLength = atoi(lp);
00108   if (_contentLength <= 0) {
00109     XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength);
00110     return false;
00111   }
00112         
00113   XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength);
00114 
00115   // Otherwise copy non-header data to request buffer and set state to read request.
00116   _request = bp;
00117 
00118   // Parse out any interesting bits from the header (HTTP version, connection)
00119   _keepAlive = true;
00120   if (_header.find("HTTP/1.0") != std::string::npos) {
00121     if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0)
00122       _keepAlive = false;           // Default for HTTP 1.0 is to close the connection
00123   } else {
00124     if (kp != 0 && strncasecmp(kp, "close", 5) == 0)
00125       _keepAlive = false;
00126   }
00127   XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive);
00128 
00129 
00130   _header = ""; 
00131   _connectionState = READ_REQUEST;
00132   return true;    // Continue monitoring this source
00133 }

bool XmlRpcServerConnection::readRequest (  )  [protected]

Reads the request (based on the content-length header value).

00139 {
00140   // If we dont have the entire request yet, read available data
00141   if (int(_request.length()) < _contentLength) {
00142     bool eof;
00143     if ( ! XmlRpcSocket::nbRead(this->getfd(), _request, &eof, _ssl_ssl)) {
00144       XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
00145       return false;
00146     }
00147 
00148     // If we haven't gotten the entire request yet, return (keep reading)
00149     if (int(_request.length()) < _contentLength) {
00150       if (eof) {
00151         XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request");
00152         return false;   // Either way we close the connection
00153       }
00154       return true;
00155     }
00156   }
00157 
00158   // Otherwise, parse and dispatch the request
00159   XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length());
00160   //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str());
00161 
00162   _connectionState = WRITE_RESPONSE;
00163 
00164   return true;    // Continue monitoring this source
00165 }

bool XmlRpcServerConnection::writeResponse (  )  [protected]

Executes the request and writes the resulting response.

00171 {
00172   if (_response.length() == 0) {
00173     executeRequest();
00174     _bytesWritten = 0;
00175     if (_response.length() == 0) {
00176       XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response.");
00177       return false;
00178     }
00179   }
00180 
00181   // Try to write the response
00182   if ( ! XmlRpcSocket::nbWrite(this->getfd(), _response, &_bytesWritten, _ssl_ssl)) {
00183     XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
00184     return false;
00185   }
00186   XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length());
00187 
00188   // Prepare to read the next request
00189   if (_bytesWritten == int(_response.length())) {
00190     _header = "";
00191     _request = "";
00192     _response = "";
00193     _connectionState = READ_HEADER;
00194   }
00195 
00196   return _keepAlive;    // Continue monitoring this source if true
00197 }

void XmlRpcServerConnection::executeRequest (  )  [protected, virtual]

Helper method to execute the client request.

00202 {
00203   _response = _server->executeRequest(_request);
00204 }


Member Data Documentation

XmlRpcServer* XmlRpc::XmlRpcServerConnection::_server [protected]

The XmlRpc server that accepted this connection.

ServerConnectionState XmlRpc::XmlRpcServerConnection::_connectionState [protected]

Current IO state for the connection.

std::string XmlRpc::XmlRpcServerConnection::_header [protected]

Request headers.

int XmlRpc::XmlRpcServerConnection::_contentLength [protected]

Number of bytes expected in the request body (parsed from header).

std::string XmlRpc::XmlRpcServerConnection::_request [protected]

Request body.

std::string XmlRpc::XmlRpcServerConnection::_response [protected]

Response.

int XmlRpc::XmlRpcServerConnection::_bytesWritten [protected]

Number of bytes of the response written so far.

bool XmlRpc::XmlRpcServerConnection::_keepAlive [protected]

Whether to keep the current client connection open for further requests.


The documentation for this class was generated from the following files:
Generated on Tue Jul 24 16:51:19 2007 for ITM OverSim by  doxygen 1.5.1