OverSim
XmlRpcServerConnection.cc
Go to the documentation of this file.
1 
9 
10 #include "XmlRpcSocket.h"
11 #ifndef MAKEDEPEND
12 # include <stdio.h>
13 # include <stdlib.h>
14 # include <string.h>
15 #endif
16 
17 #include "XmlRpcDispatch.h"
18 #include "XmlRpcServer.h"
19 #include "XmlRpcUtil.h"
20 
21 using namespace XmlRpc;
22 
23 
24 
25 // The server delegates handling client requests to a serverConnection object.
27  XmlRpcServer* server,
28  bool deleteOnClose /*= false*/) :
29  XmlRpcSource(fd, deleteOnClose)
30 {
31  XmlRpcUtil::log(2,"XmlRpcServerConnection: new socket %d.", fd);
32  _server = server;
34  _keepAlive = true;
35 }
36 
37 
39 {
40  XmlRpcUtil::log(4,"XmlRpcServerConnection dtor.");
42 }
43 
44 
45 // Handle input on the server socket by accepting the connection
46 // and reading the rpc request. Return true to continue to monitor
47 // the socket for events, false to remove it from the dispatcher.
48 unsigned
49 XmlRpcServerConnection::handleEvent(unsigned /*eventType*/)
50 {
52  if ( ! readHeader()) return 0;
53 
55  if ( ! readRequest()) return 0;
56 
58  if ( ! writeResponse()) return 0;
59 
60  return (_connectionState == WRITE_RESPONSE)
62 }
63 
64 
65 bool
67 {
68  // Read available data
69  bool eof;
70  if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof, _ssl_ssl)) {
71  // Its only an error if we already have read some data
72  if (_header.length() > 0)
73  XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error while reading header (%s).",XmlRpcSocket::getErrorMsg().c_str());
74  return false;
75  }
76 
77  XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length());
78  char *hp = (char*)_header.c_str(); // Start of header
79  char *ep = hp + _header.length(); // End of string
80  char *bp = 0; // Start of body
81  char *lp = 0; // Start of content-length value
82  char *kp = 0; // Start of connection value
83 
84  for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
85  if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
86  lp = cp + 16;
87  else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0))
88  kp = cp + 12;
89  else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
90  bp = cp + 4;
91  else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
92  bp = cp + 2;
93  }
94 
95  // If we haven't gotten the entire header yet, return (keep reading)
96  if (bp == 0) {
97  // EOF in the middle of a request is an error, otherwise its ok
98  if (eof) {
99  XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF");
100  if (_header.length() > 0)
101  XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header");
102  return false; // Either way we close the connection
103  }
104 
105  return true; // Keep reading
106  }
107 
108  // Decode content length
109  if (lp == 0) {
110  XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified");
111  return false; // We could try to figure it out by parsing as we read, but for now...
112  }
113 
114  _contentLength = atoi(lp);
115  if (_contentLength <= 0) {
116  XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength);
117  return false;
118  }
119 
120  XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength);
121 
122  // Otherwise copy non-header data to request buffer and set state to read request.
123  _request = bp;
124 
125  // Parse out any interesting bits from the header (HTTP version, connection)
126  _keepAlive = true;
127  if (_header.find("HTTP/1.0") != std::string::npos) {
128  if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0)
129  _keepAlive = false; // Default for HTTP 1.0 is to close the connection
130  } else {
131  if (kp != 0 && strncasecmp(kp, "close", 5) == 0)
132  _keepAlive = false;
133  }
134  XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive);
135 
136 
137  _header = "";
139  return true; // Continue monitoring this source
140 }
141 
142 
143 
144 bool
146 {
147  // If we dont have the entire request yet, read available data
148  if (int(_request.length()) < _contentLength) {
149  bool eof;
150  if ( ! XmlRpcSocket::nbRead(this->getfd(), _request, &eof, _ssl_ssl)) {
151  XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
152  return false;
153  }
154 
155  // If we haven't gotten the entire request yet, return (keep reading)
156  if (int(_request.length()) < _contentLength) {
157  if (eof) {
158  XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request");
159  return false; // Either way we close the connection
160  }
161  return true;
162  }
163  }
164 
165  // Otherwise, parse and dispatch the request
166  XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length());
167  //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str());
168 
170 
171  return true; // Continue monitoring this source
172 }
173 
174 
175 
176 bool
178 {
179  if (_response.length() == 0) {
180  executeRequest();
181  _bytesWritten = 0;
182  if (_response.length() == 0) {
183  XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response.");
184  return false;
185  }
186  }
187 
188  // Try to write the response
190  XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
191  return false;
192  }
193  XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length());
194 
195  // Prepare to read the next request
196  if (_bytesWritten == int(_response.length())) {
197  _header = "";
198  _request = "";
199  _response = "";
201  }
202 
203  return _keepAlive; // Continue monitoring this source if true
204 }
205 
206 
209 {
211 }
212