Public Member Functions | Protected Types | Protected Member Functions | Protected Attributes

XmlRpc::XmlRpcServerConnection Class Reference

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

#include <XmlRpcServerConnection.h>

Inheritance diagram for XmlRpc::XmlRpcServerConnection:
XmlRpc::XmlRpcSource

List of all members.

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.

Detailed Description

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

Definition at line 31 of file XmlRpcServerConnection.h.


Member Enumeration Documentation

Possible IO states for the connection.

Enumerator:
READ_HEADER 
READ_REQUEST 
WRITE_RESPONSE 

Definition at line 64 of file XmlRpcServerConnection.h.

{ READ_HEADER, READ_REQUEST, WRITE_RESPONSE };


Constructor & Destructor Documentation

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

Constructor.

Definition at line 26 of file XmlRpcServerConnection.cc.

                                                                               :
  XmlRpcSource(fd, deleteOnClose)
{
  XmlRpcUtil::log(2,"XmlRpcServerConnection: new socket %d.", fd);
  _server = server;
  _connectionState = READ_HEADER;
  _keepAlive = true;
}

XmlRpcServerConnection::~XmlRpcServerConnection (  )  [virtual]

Destructor.

Definition at line 38 of file XmlRpcServerConnection.cc.

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


Member Function Documentation

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

Helper method to execute the client request.

Definition at line 208 of file XmlRpcServerConnection.cc.

Referenced by writeResponse().

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.

Definition at line 49 of file XmlRpcServerConnection.cc.

{
  if (_connectionState == READ_HEADER)
    if ( ! readHeader()) return 0;

  if (_connectionState == READ_REQUEST)
    if ( ! readRequest()) return 0;

  if (_connectionState == WRITE_RESPONSE)
    if ( ! writeResponse()) return 0;

  return (_connectionState == WRITE_RESPONSE) 
        ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
}

bool XmlRpcServerConnection::readHeader (  )  [protected]

Reads the http header.

Definition at line 66 of file XmlRpcServerConnection.cc.

Referenced by handleEvent().

{
  // Read available data
  bool eof;
  if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof, _ssl_ssl)) {
    // Its only an error if we already have read some data
    if (_header.length() > 0)
      XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error while reading header (%s).",XmlRpcSocket::getErrorMsg().c_str());
    return false;
  }

  XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length());
  char *hp = (char*)_header.c_str();  // Start of header
  char *ep = hp + _header.length();   // End of string
  char *bp = 0;                       // Start of body
  char *lp = 0;                       // Start of content-length value
  char *kp = 0;                       // Start of connection value

  for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
        if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
          lp = cp + 16;
        else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0))
          kp = cp + 12;
        else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
          bp = cp + 4;
        else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
          bp = cp + 2;
  }

  // If we haven't gotten the entire header yet, return (keep reading)
  if (bp == 0) {
    // EOF in the middle of a request is an error, otherwise its ok
    if (eof) {
      XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF");
      if (_header.length() > 0)
        XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header");
      return false;   // Either way we close the connection
    }
    
    return true;  // Keep reading
  }

  // Decode content length
  if (lp == 0) {
    XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified");
    return false;   // We could try to figure it out by parsing as we read, but for now...
  }

  _contentLength = atoi(lp);
  if (_contentLength <= 0) {
    XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength);
    return false;
  }
        
  XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength);

  // Otherwise copy non-header data to request buffer and set state to read request.
  _request = bp;

  // Parse out any interesting bits from the header (HTTP version, connection)
  _keepAlive = true;
  if (_header.find("HTTP/1.0") != std::string::npos) {
    if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0)
      _keepAlive = false;           // Default for HTTP 1.0 is to close the connection
  } else {
    if (kp != 0 && strncasecmp(kp, "close", 5) == 0)
      _keepAlive = false;
  }
  XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive);


  _header = ""; 
  _connectionState = READ_REQUEST;
  return true;    // Continue monitoring this source
}

bool XmlRpcServerConnection::readRequest (  )  [protected]

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

Definition at line 145 of file XmlRpcServerConnection.cc.

Referenced by handleEvent().

{
  // If we dont have the entire request yet, read available data
  if (int(_request.length()) < _contentLength) {
    bool eof;
    if ( ! XmlRpcSocket::nbRead(this->getfd(), _request, &eof, _ssl_ssl)) {
      XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
      return false;
    }

    // If we haven't gotten the entire request yet, return (keep reading)
    if (int(_request.length()) < _contentLength) {
      if (eof) {
        XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request");
        return false;   // Either way we close the connection
      }
      return true;
    }
  }

  // Otherwise, parse and dispatch the request
  XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length());
  //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str());

  _connectionState = WRITE_RESPONSE;

  return true;    // Continue monitoring this source
}

bool XmlRpcServerConnection::writeResponse (  )  [protected]

Executes the request and writes the resulting response.

Definition at line 177 of file XmlRpcServerConnection.cc.

Referenced by handleEvent().

{
  if (_response.length() == 0) {
    executeRequest();
    _bytesWritten = 0;
    if (_response.length() == 0) {
      XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response.");
      return false;
    }
  }

  // Try to write the response
  if ( ! XmlRpcSocket::nbWrite(this->getfd(), _response, &_bytesWritten, _ssl_ssl)) {
    XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
    return false;
  }
  XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length());

  // Prepare to read the next request
  if (_bytesWritten == int(_response.length())) {
    _header = "";
    _request = "";
    _response = "";
    _connectionState = READ_HEADER;
  }

  return _keepAlive;    // Continue monitoring this source if true
}


Member Data Documentation

Number of bytes of the response written so far.

Definition at line 81 of file XmlRpcServerConnection.h.

Referenced by writeResponse().

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

Definition at line 72 of file XmlRpcServerConnection.h.

Referenced by readHeader(), and readRequest().

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

Request headers.

Definition at line 69 of file XmlRpcServerConnection.h.

Referenced by readHeader(), and writeResponse().

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

Definition at line 84 of file XmlRpcServerConnection.h.

Referenced by readHeader(), writeResponse(), and XmlRpcServerConnection().

Request body.

Definition at line 75 of file XmlRpcServerConnection.h.

Referenced by executeRequest(), readHeader(), readRequest(), and writeResponse().

Response.

Definition at line 78 of file XmlRpcServerConnection.h.

Referenced by executeRequest(), and writeResponse().

The XmlRpc server that accepted this connection.

Definition at line 61 of file XmlRpcServerConnection.h.

Referenced by executeRequest(), XmlRpcServerConnection(), and ~XmlRpcServerConnection().


The documentation for this class was generated from the following files: