~efargaspro/+junk/codeblocks-16.01-release

« back to all changes in this revision

Viewing changes to src/plugins/contrib/PythonPlugins/XmlRpcEmbedder/XMLRPC/src/XmlRpcServerConnection.cpp

  • Committer: damienlmoore at gmail
  • Date: 2016-02-02 02:43:22 UTC
  • Revision ID: damienlmoore@gmail.com-20160202024322-yql5qmtbwdyamdwd
Code::BlocksĀ 16.01

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
#include "XmlRpcServerConnection.h"
 
3
 
 
4
#include "XmlRpcSocket.h"
 
5
#include "XmlRpc.h"
 
6
#ifndef MAKEDEPEND
 
7
# include <stdio.h>
 
8
# include <stdlib.h>
 
9
#endif
 
10
 
 
11
#include <cstring>
 
12
 
 
13
using namespace XmlRpc;
 
14
 
 
15
// Static data
 
16
const char XmlRpcServerConnection::METHODNAME_TAG[] = "<methodName>";
 
17
const char XmlRpcServerConnection::PARAMS_TAG[] = "<params>";
 
18
const char XmlRpcServerConnection::PARAMS_ETAG[] = "</params>";
 
19
const char XmlRpcServerConnection::PARAM_TAG[] = "<param>";
 
20
const char XmlRpcServerConnection::PARAM_ETAG[] = "</param>";
 
21
 
 
22
const std::string XmlRpcServerConnection::SYSTEM_MULTICALL = "system.multicall";
 
23
const std::string XmlRpcServerConnection::METHODNAME = "methodName";
 
24
const std::string XmlRpcServerConnection::PARAMS = "params";
 
25
 
 
26
const std::string XmlRpcServerConnection::FAULTCODE = "faultCode";
 
27
const std::string XmlRpcServerConnection::FAULTSTRING = "faultString";
 
28
 
 
29
 
 
30
 
 
31
// The server delegates handling client requests to a serverConnection object.
 
32
XmlRpcServerConnection::XmlRpcServerConnection(int fd, XmlRpcServer* server, bool deleteOnClose /*= false*/) :
 
33
  XmlRpcSource(fd, deleteOnClose)
 
34
{
 
35
  XmlRpcUtil::log(2,"XmlRpcServerConnection: new socket %d.", fd);
 
36
  _server = server;
 
37
  _connectionState = READ_HEADER;
 
38
  _keepAlive = true;
 
39
}
 
40
 
 
41
 
 
42
XmlRpcServerConnection::~XmlRpcServerConnection()
 
43
{
 
44
  XmlRpcUtil::log(4,"XmlRpcServerConnection dtor.");
 
45
  _server->removeConnection(this);
 
46
}
 
47
 
 
48
 
 
49
// Handle input on the server socket by accepting the connection
 
50
// and reading the rpc request. Return true to continue to monitor
 
51
// the socket for events, false to remove it from the dispatcher.
 
52
unsigned
 
53
XmlRpcServerConnection::handleEvent(unsigned /*eventType*/)
 
54
{
 
55
  if (_connectionState == READ_HEADER)
 
56
    if ( ! readHeader()) return 0;
 
57
 
 
58
  if (_connectionState == READ_REQUEST)
 
59
    if ( ! readRequest()) return 0;
 
60
 
 
61
  if (_connectionState == WRITE_RESPONSE)
 
62
    if ( ! writeResponse()) return 0;
 
63
 
 
64
  return (_connectionState == WRITE_RESPONSE)
 
65
        ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
 
66
}
 
67
 
 
68
 
 
69
bool
 
70
XmlRpcServerConnection::readHeader()
 
71
{
 
72
  // Read available data
 
73
  bool eof;
 
74
  if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof)) {
 
75
    // Its only an error if we already have read some data
 
76
    if (_header.length() > 0)
 
77
      XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error while reading header (%s).",XmlRpcSocket::getErrorMsg().c_str());
 
78
    return false;
 
79
  }
 
80
 
 
81
  XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length());
 
82
  char *hp = (char*)_header.c_str();  // Start of header
 
83
  char *ep = hp + _header.length();   // End of string
 
84
  char *bp = 0;                       // Start of body
 
85
  char *lp = 0;                       // Start of content-length value
 
86
  char *kp = 0;                       // Start of connection value
 
87
 
 
88
  for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
 
89
        if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
 
90
          lp = cp + 16;
 
91
        else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0))
 
92
          kp = cp + 12;
 
93
        else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
 
94
          bp = cp + 4;
 
95
        else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
 
96
          bp = cp + 2;
 
97
  }
 
98
 
 
99
  // If we haven't gotten the entire header yet, return (keep reading)
 
100
  if (bp == 0) {
 
101
    // EOF in the middle of a request is an error, otherwise its ok
 
102
    if (eof) {
 
103
      XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF");
 
104
      if (_header.length() > 0)
 
105
        XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header");
 
106
      return false;   // Either way we close the connection
 
107
    }
 
108
 
 
109
    return true;  // Keep reading
 
110
  }
 
111
 
 
112
  // Decode content length
 
113
  if (lp == 0) {
 
114
    XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified");
 
115
    return false;   // We could try to figure it out by parsing as we read, but for now...
 
116
  }
 
117
 
 
118
  _contentLength = atoi(lp);
 
119
  if (_contentLength <= 0) {
 
120
    XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength);
 
121
    return false;
 
122
  }
 
123
 
 
124
  XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength);
 
125
 
 
126
  // Otherwise copy non-header data to request buffer and set state to read request.
 
127
  _request = bp;
 
128
 
 
129
  // Parse out any interesting bits from the header (HTTP version, connection)
 
130
  _keepAlive = true;
 
131
  if (_header.find("HTTP/1.0") != std::string::npos) {
 
132
    if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0)
 
133
      _keepAlive = false;           // Default for HTTP 1.0 is to close the connection
 
134
  } else {
 
135
    if (kp != 0 && strncasecmp(kp, "close", 5) == 0)
 
136
      _keepAlive = false;
 
137
  }
 
138
  XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive);
 
139
 
 
140
 
 
141
  _header = "";
 
142
  _connectionState = READ_REQUEST;
 
143
  return true;    // Continue monitoring this source
 
144
}
 
145
 
 
146
bool
 
147
XmlRpcServerConnection::readRequest()
 
148
{
 
149
  // If we dont have the entire request yet, read available data
 
150
  if (int(_request.length()) < _contentLength) {
 
151
    bool eof;
 
152
    if ( ! XmlRpcSocket::nbRead(this->getfd(), _request, &eof)) {
 
153
      XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
 
154
      return false;
 
155
    }
 
156
 
 
157
    // If we haven't gotten the entire request yet, return (keep reading)
 
158
    if (int(_request.length()) < _contentLength) {
 
159
      if (eof) {
 
160
        XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request");
 
161
        return false;   // Either way we close the connection
 
162
      }
 
163
      return true;
 
164
    }
 
165
  }
 
166
 
 
167
  // Otherwise, parse and dispatch the request
 
168
  XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length());
 
169
  //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str());
 
170
 
 
171
  _connectionState = WRITE_RESPONSE;
 
172
 
 
173
  return true;    // Continue monitoring this source
 
174
}
 
175
 
 
176
 
 
177
bool
 
178
XmlRpcServerConnection::writeResponse()
 
179
{
 
180
  if (_response.length() == 0) {
 
181
    executeRequest();
 
182
    _bytesWritten = 0;
 
183
    if (_response.length() == 0) {
 
184
      XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response.");
 
185
      return false;
 
186
    }
 
187
  }
 
188
 
 
189
  // Try to write the response
 
190
  if ( ! XmlRpcSocket::nbWrite(this->getfd(), _response, &_bytesWritten)) {
 
191
    XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
 
192
    return false;
 
193
  }
 
194
  XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length());
 
195
 
 
196
  // Prepare to read the next request
 
197
  if (_bytesWritten == int(_response.length())) {
 
198
    _header = "";
 
199
    _request = "";
 
200
    _response = "";
 
201
    _connectionState = READ_HEADER;
 
202
  }
 
203
 
 
204
  return _keepAlive;    // Continue monitoring this source if true
 
205
}
 
206
 
 
207
// Run the method, generate _response string
 
208
void
 
209
XmlRpcServerConnection::executeRequest()
 
210
{
 
211
  XmlRpcValue params, resultValue;
 
212
  std::string methodName = parseRequest(params);
 
213
  XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: server calling method '%s'",
 
214
                    methodName.c_str());
 
215
 
 
216
  try {
 
217
 
 
218
    if ( ! executeMethod(methodName, params, resultValue) &&
 
219
         ! executeMulticall(methodName, params, resultValue))
 
220
      generateFaultResponse(methodName + ": unknown method name");
 
221
    else
 
222
      generateResponse(resultValue.toXml());
 
223
 
 
224
  } catch (const XmlRpcException& fault) {
 
225
    XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: fault %s.",
 
226
                    fault.getMessage().c_str());
 
227
    generateFaultResponse(fault.getMessage(), fault.getCode());
 
228
  }
 
229
}
 
230
 
 
231
// Parse the method name and the argument values from the request.
 
232
std::string
 
233
XmlRpcServerConnection::parseRequest(XmlRpcValue& params)
 
234
{
 
235
  int offset = 0;   // Number of chars parsed from the request
 
236
 
 
237
  std::string methodName = XmlRpcUtil::parseTag(METHODNAME_TAG, _request, &offset);
 
238
 
 
239
  if (methodName.size() > 0 && XmlRpcUtil::findTag(PARAMS_TAG, _request, &offset))
 
240
  {
 
241
    int nArgs = 0;
 
242
    while (XmlRpcUtil::nextTagIs(PARAM_TAG, _request, &offset)) {
 
243
      params[nArgs++] = XmlRpcValue(_request, &offset);
 
244
      (void) XmlRpcUtil::nextTagIs(PARAM_ETAG, _request, &offset);
 
245
    }
 
246
 
 
247
    (void) XmlRpcUtil::nextTagIs(PARAMS_ETAG, _request, &offset);
 
248
  }
 
249
 
 
250
  return methodName;
 
251
}
 
252
 
 
253
// Execute a named method with the specified params.
 
254
bool
 
255
XmlRpcServerConnection::executeMethod(const std::string& methodName,
 
256
                                      XmlRpcValue& params, XmlRpcValue& result)
 
257
{
 
258
  XmlRpcServerMethod* method = _server->findMethod(methodName);
 
259
 
 
260
  if ( ! method) return false;
 
261
 
 
262
  method->execute(params, result);
 
263
 
 
264
  // Ensure a valid result value
 
265
  if ( ! result.valid())
 
266
      result = std::string();
 
267
 
 
268
  return true;
 
269
}
 
270
 
 
271
// Execute multiple calls and return the results in an array.
 
272
bool
 
273
XmlRpcServerConnection::executeMulticall(const std::string& methodName,
 
274
                                         XmlRpcValue& params, XmlRpcValue& result)
 
275
{
 
276
  if (methodName != SYSTEM_MULTICALL) return false;
 
277
 
 
278
  // There ought to be 1 parameter, an array of structs
 
279
  if (params.size() != 1 || params[0].getType() != XmlRpcValue::TypeArray)
 
280
    throw XmlRpcException(SYSTEM_MULTICALL + ": Invalid argument (expected an array)");
 
281
 
 
282
  int nc = params[0].size();
 
283
  result.setSize(nc);
 
284
 
 
285
  for (int i=0; i<nc; ++i) {
 
286
 
 
287
    if ( ! params[0][i].hasMember(METHODNAME) ||
 
288
         ! params[0][i].hasMember(PARAMS)) {
 
289
      result[i][FAULTCODE] = -1;
 
290
      result[i][FAULTSTRING] = SYSTEM_MULTICALL +
 
291
              ": Invalid argument (expected a struct with members methodName and params)";
 
292
      continue;
 
293
    }
 
294
 
 
295
    const std::string& methodName = params[0][i][METHODNAME];
 
296
    XmlRpcValue& methodParams = params[0][i][PARAMS];
 
297
 
 
298
    XmlRpcValue resultValue;
 
299
    resultValue.setSize(1);
 
300
    try {
 
301
      if ( ! executeMethod(methodName, methodParams, resultValue[0]) &&
 
302
           ! executeMulticall(methodName, params, resultValue[0]))
 
303
      {
 
304
        result[i][FAULTCODE] = -1;
 
305
        result[i][FAULTSTRING] = methodName + ": unknown method name";
 
306
      }
 
307
      else
 
308
        result[i] = resultValue;
 
309
 
 
310
    } catch (const XmlRpcException& fault) {
 
311
        result[i][FAULTCODE] = fault.getCode();
 
312
        result[i][FAULTSTRING] = fault.getMessage();
 
313
    }
 
314
  }
 
315
 
 
316
  return true;
 
317
}
 
318
 
 
319
 
 
320
// Create a response from results xml
 
321
void
 
322
XmlRpcServerConnection::generateResponse(std::string const& resultXml)
 
323
{
 
324
  const char RESPONSE_1[] =
 
325
    "<?xml version=\"1.0\"?>\r\n"
 
326
    "<methodResponse><params><param>\r\n\t";
 
327
  const char RESPONSE_2[] =
 
328
    "\r\n</param></params></methodResponse>\r\n";
 
329
 
 
330
  std::string body = RESPONSE_1 + resultXml + RESPONSE_2;
 
331
  std::string header = generateHeader(body);
 
332
 
 
333
  _response = header + body;
 
334
  XmlRpcUtil::log(5, "XmlRpcServerConnection::generateResponse:\n%s\n", _response.c_str());
 
335
}
 
336
 
 
337
// Prepend http headers
 
338
std::string
 
339
XmlRpcServerConnection::generateHeader(std::string const& body)
 
340
{
 
341
  std::string header =
 
342
    "HTTP/1.1 200 OK\r\n"
 
343
    "Server: ";
 
344
  header += XMLRPC_VERSION;
 
345
  header += "\r\n"
 
346
    "Content-Type: text/xml\r\n"
 
347
    "Content-length: ";
 
348
 
 
349
  char buffLen[40];
 
350
  sprintf(buffLen,"%d\r\n\r\n", body.size());
 
351
 
 
352
  return header + buffLen;
 
353
}
 
354
 
 
355
 
 
356
void
 
357
XmlRpcServerConnection::generateFaultResponse(std::string const& errorMsg, int errorCode)
 
358
{
 
359
  const char RESPONSE_1[] =
 
360
    "<?xml version=\"1.0\"?>\r\n"
 
361
    "<methodResponse><fault>\r\n\t";
 
362
  const char RESPONSE_2[] =
 
363
    "\r\n</fault></methodResponse>\r\n";
 
364
 
 
365
  XmlRpcValue faultStruct;
 
366
  faultStruct[FAULTCODE] = errorCode;
 
367
  faultStruct[FAULTSTRING] = errorMsg;
 
368
  std::string body = RESPONSE_1 + faultStruct.toXml() + RESPONSE_2;
 
369
  std::string header = generateHeader(body);
 
370
 
 
371
  _response = header + body;
 
372
}
 
373