#include <XmlRpcServerConnection.h>
Inheritance diagram for XmlRpc::XmlRpcServerConnection:
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. |
enum XmlRpc::XmlRpcServerConnection::ServerConnectionState [protected] |
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 }
unsigned XmlRpcServerConnection::handleEvent | ( | unsigned | eventType | ) | [virtual] |
Handle IO on the client connection socket.
eventType | Type of IO event that occurred. |
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 }
XmlRpcServer* XmlRpc::XmlRpcServerConnection::_server [protected] |
The XmlRpc server that accepted this connection.
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.