XmlRpcServerConnection.cc

Go to the documentation of this file.
00001 
00008 #include "XmlRpcServerConnection.h"
00009 
00010 #include "XmlRpcSocket.h"
00011 #ifndef MAKEDEPEND
00012 # include <stdio.h>
00013 # include <stdlib.h>
00014 # include <string.h>
00015 #endif
00016 
00017 #include "XmlRpcDispatch.h"
00018 #include "XmlRpcServer.h"
00019 #include "XmlRpcUtil.h"
00020 
00021 using namespace XmlRpc;
00022 
00023 
00024 
00025 // The server delegates handling client requests to a serverConnection object.
00026 XmlRpcServerConnection::XmlRpcServerConnection(int fd,
00027                                                XmlRpcServer* server,
00028                                                bool deleteOnClose /*= false*/) :
00029   XmlRpcSource(fd, deleteOnClose)
00030 {
00031   XmlRpcUtil::log(2,"XmlRpcServerConnection: new socket %d.", fd);
00032   _server = server;
00033   _connectionState = READ_HEADER;
00034   _keepAlive = true;
00035 }
00036 
00037 
00038 XmlRpcServerConnection::~XmlRpcServerConnection()
00039 {
00040   XmlRpcUtil::log(4,"XmlRpcServerConnection dtor.");
00041   _server->removeConnection(this);
00042 }
00043 
00044 
00045 // Handle input on the server socket by accepting the connection
00046 // and reading the rpc request. Return true to continue to monitor
00047 // the socket for events, false to remove it from the dispatcher.
00048 unsigned
00049 XmlRpcServerConnection::handleEvent(unsigned /*eventType*/)
00050 {
00051   if (_connectionState == READ_HEADER)
00052     if ( ! readHeader()) return 0;
00053 
00054   if (_connectionState == READ_REQUEST)
00055     if ( ! readRequest()) return 0;
00056 
00057   if (_connectionState == WRITE_RESPONSE)
00058     if ( ! writeResponse()) return 0;
00059 
00060   return (_connectionState == WRITE_RESPONSE) 
00061         ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
00062 }
00063 
00064 
00065 bool
00066 XmlRpcServerConnection::readHeader()
00067 {
00068   // Read available data
00069   bool eof;
00070   if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof, _ssl_ssl)) {
00071     // Its only an error if we already have read some data
00072     if (_header.length() > 0)
00073       XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error while reading header (%s).",XmlRpcSocket::getErrorMsg().c_str());
00074     return false;
00075   }
00076 
00077   XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length());
00078   char *hp = (char*)_header.c_str();  // Start of header
00079   char *ep = hp + _header.length();   // End of string
00080   char *bp = 0;                       // Start of body
00081   char *lp = 0;                       // Start of content-length value
00082   char *kp = 0;                       // Start of connection value
00083 
00084   for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
00085         if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
00086           lp = cp + 16;
00087         else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0))
00088           kp = cp + 12;
00089         else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
00090           bp = cp + 4;
00091         else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
00092           bp = cp + 2;
00093   }
00094 
00095   // If we haven't gotten the entire header yet, return (keep reading)
00096   if (bp == 0) {
00097     // EOF in the middle of a request is an error, otherwise its ok
00098     if (eof) {
00099       XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF");
00100       if (_header.length() > 0)
00101         XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header");
00102       return false;   // Either way we close the connection
00103     }
00104     
00105     return true;  // Keep reading
00106   }
00107 
00108   // Decode content length
00109   if (lp == 0) {
00110     XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified");
00111     return false;   // We could try to figure it out by parsing as we read, but for now...
00112   }
00113 
00114   _contentLength = atoi(lp);
00115   if (_contentLength <= 0) {
00116     XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength);
00117     return false;
00118   }
00119         
00120   XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength);
00121 
00122   // Otherwise copy non-header data to request buffer and set state to read request.
00123   _request = bp;
00124 
00125   // Parse out any interesting bits from the header (HTTP version, connection)
00126   _keepAlive = true;
00127   if (_header.find("HTTP/1.0") != std::string::npos) {
00128     if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0)
00129       _keepAlive = false;           // Default for HTTP 1.0 is to close the connection
00130   } else {
00131     if (kp != 0 && strncasecmp(kp, "close", 5) == 0)
00132       _keepAlive = false;
00133   }
00134   XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive);
00135 
00136 
00137   _header = ""; 
00138   _connectionState = READ_REQUEST;
00139   return true;    // Continue monitoring this source
00140 }
00141 
00142 
00143 
00144 bool
00145 XmlRpcServerConnection::readRequest()
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, _ssl_ssl)) {
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 }
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   // Try to write the response
00189   if ( ! XmlRpcSocket::nbWrite(this->getfd(), _response, &_bytesWritten, _ssl_ssl)) {
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   // Prepare to read the next request
00196   if (_bytesWritten == int(_response.length())) {
00197     _header = "";
00198     _request = "";
00199     _response = "";
00200     _connectionState = READ_HEADER;
00201   }
00202 
00203   return _keepAlive;    // Continue monitoring this source if true
00204 }
00205 
00206 
00208 void XmlRpcServerConnection::executeRequest()
00209 {
00210   _response = _server->executeRequest(_request);
00211 }
00212 
Generated on Wed May 26 16:21:15 2010 for OverSim by  doxygen 1.6.3