diff options
| author | deva <deva> | 2010-05-07 09:31:26 +0000 | 
|---|---|---|
| committer | deva <deva> | 2010-05-07 09:31:26 +0000 | 
| commit | 965e43178736e6635cf27410e6d73f4ec0fdced2 (patch) | |
| tree | 7cc297f68e93f6974baaf185259ac88f35df0355 /server/src | |
| parent | 3241d29dec9beb0c367340465bd8d9bcab863692 (diff) | |
LOTS of changes. libmicrohttpd fix for 'chunked' POST handling and LUA parameter checker from Pentominos among other things.
Diffstat (limited to 'server/src')
| -rw-r--r-- | server/src/Makefile.am | 2 | ||||
| -rw-r--r-- | server/src/artefact.cc | 97 | ||||
| -rw-r--r-- | server/src/debug.cc | 2 | ||||
| -rw-r--r-- | server/src/entitylist.cc | 8 | ||||
| -rw-r--r-- | server/src/inotify.cc | 9 | ||||
| -rw-r--r-- | server/src/luaresume.cc | 34 | ||||
| -rw-r--r-- | server/src/luautil.cc | 312 | ||||
| -rw-r--r-- | server/src/luautil.h | 81 | ||||
| -rw-r--r-- | server/src/macrolist.cc | 5 | ||||
| -rw-r--r-- | server/src/saxparser.cc | 25 | ||||
| -rw-r--r-- | server/src/server.cc | 200 | ||||
| -rw-r--r-- | server/src/session.cc | 13 | ||||
| -rw-r--r-- | server/src/session.h | 8 | ||||
| -rw-r--r-- | server/src/templatelist.cc | 5 | ||||
| -rw-r--r-- | server/src/transactionhandler.cc | 27 | ||||
| -rw-r--r-- | server/src/transactionparser.cc | 73 | 
16 files changed, 725 insertions, 176 deletions
| diff --git a/server/src/Makefile.am b/server/src/Makefile.am index 1ff8a3a..afc72f9 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -27,6 +27,7 @@ pracrod_SOURCES = \  	log.cc \  	luaquerymapper.cc \  	luaresume.cc \ +	luautil.cc \  	macroheaderparser.cc \  	macrolist.cc \  	macroparser.cc \ @@ -102,6 +103,7 @@ EXTRA_DIST = \  	log.h \  	luaquerymapper.h \  	luaresume.h \ +	luautil.h \  	macroheaderparser.h \  	macrolist.h \  	macroparser.h \ diff --git a/server/src/artefact.cc b/server/src/artefact.cc index cc29b77..24114f9 100644 --- a/server/src/artefact.cc +++ b/server/src/artefact.cc @@ -35,7 +35,7 @@  Artefact::Artefact()  {  #ifndef WITHOUT_PENTOMINOS -  PRACRO_DEBUG(artefact, "Creating artefact connection %s : %d", +  PRACRO_DEBUG(artefact, "Creating artefact connection %s : %d\n",                 Conf::artefact_addr.c_str(), Conf::artefact_port);  #endif/*WITHOUT_PENTOMINOS*/ @@ -54,47 +54,88 @@ Artefact::~Artefact()    atf_close(atfh);  } +static QueryResult node2result(atf_result_node_t *node, time_t timestamp) +{ +  QueryResult rnode; +  rnode.timestamp = timestamp; +  rnode.source = "pentominos"; + +  if(!node) return rnode; + +  struct _atf_result_node_t *child = node->child; +  while(child) { +    if(child->value == NULL) { +      rnode.groups[child->name] = node2result(child, timestamp); +    } else { +      rnode.values[child->name] = child->value; +    } +    child = child->next; +  } + +  return rnode; +} +  QueryResult Artefact::exec(Query &query,                             std::string patientid,                             std::string user)  { -  QueryParser parser; +  atf_transaction_t* atft = NULL; +  atf_reply_t *reply = NULL; +  atf_result_t *result = NULL; +  atf_result_node_t *root = NULL; +  atf_status_t status; +  time_t timestamp; +  atf_id id; + +  QueryResult rroot; +  rroot.timestamp = 0; +  rroot.source = "pentominos"; + +  if(query.attributes.find("class") == query.attributes.end()) { +    PRACRO_ERR(artefact, "Missing 'class' attribute!\n"); +    goto aaarg; +  } -  atf_transaction_t *trans = atf_new_transaction(conn, patientid.c_str()); -  atf_querylist_t *qlist = atf_new_querylist(trans, user.c_str()); +  atft = atf_new_transaction(conn, patientid.c_str()); +  if(!atft) goto aaarg; -  atf_id id = atf_add_query(qlist, -                            query.attributes["class"].c_str(), -                            0/*oldest*/, "xml"/*replyformat*/); +  id = atf_add_query(atft, query.attributes["class"].c_str(), +                     FILTER_LATEST, USE_NONE, 0, 0); +  if(!atft) goto aaarg; -  atf_reply_t *reply = atf_commit(trans, NULL, qlist); +  reply = atf_commit(atft); +  if(!reply) goto aaarg; -  atf_status_t status = atf_get_reply_status(reply, id); +  if(atf_get_num_results(reply, id) != 1) goto aaarg; -  switch(status) { -  case ATF_STATUS_OK: -    { -      size_t bufsize = atf_get_reply_size(reply, id); -      char *buf = new char[bufsize]; -       -      ssize_t size = atf_get_reply_data(reply, id, buf, size); -      parser.parse(buf, size); -       -      delete[] buf; -    } -    break; +  result = atf_get_result(reply, id, 0); +  if(!result) goto aaarg; + +  status = atf_get_result_status(result, NULL, 0); +  if(status != ATF_STATUS_OK) goto aaarg; +  +  timestamp = atf_get_result_timestamp(result); +  rroot.timestamp = timestamp; -  case ATF_STATUS_ERROR: -    PRACRO_ERR(artefact, "Error in artefact query.\n"); -    break; +  root = atf_get_result_node(result); +  if(!root) goto aaarg; + +  { +    QueryResult qresult = node2result(root, timestamp); +    rroot.groups[query.attributes["class"]] = qresult;    } -  atf_free_reply(reply); +  goto cleanup; + + aaarg: +  PRACRO_ERR(artefact, "Artefact comm error (%d)!\n", atf_get_last_error(atfh)); -  atf_free_querylist(qlist); -  atf_free_transaction(trans); + cleanup: +  if(root) atf_free_result_node(root); +  if(reply) atf_free_reply(reply); +  if(atft) atf_free_transaction(atft); -  return parser.result; +  return rroot;  } diff --git a/server/src/debug.cc b/server/src/debug.cc index 54a2191..8bb45db 100644 --- a/server/src/debug.cc +++ b/server/src/debug.cc @@ -37,7 +37,7 @@  #define NELEM(x)	(sizeof(x)/sizeof((x)[0]))  struct __pracro_debug_channel  { -	char		name[16]; +	char		name[64];  	unsigned	flags;  }; diff --git a/server/src/entitylist.cc b/server/src/entitylist.cc index 04533c0..3ec15a5 100644 --- a/server/src/entitylist.cc +++ b/server/src/entitylist.cc @@ -197,11 +197,15 @@ std::string EntityList::getLatestVersion(std::string entity) throw(Exception)    updateList(); -  if(find(entity) == end()) +  if(find(entity) == end()) {      throw Exception("Entity ("+entityname+") ["+entity+"] does not exist"); +  } +    EntityListItem mli = (*this)[entity]; -  if(mli.size() == 0) +  if(mli.size() == 0) {      throw Exception("Entity ("+entityname+") ["+entity+"] does not exist."); +  } +    PRACRO_DEBUG(entitylist, "Search for %s - found %s v%s\n",                 entity.c_str(),                 mli.begin()->second.c_str(), diff --git a/server/src/inotify.cc b/server/src/inotify.cc index 5fb983e..1515387 100644 --- a/server/src/inotify.cc +++ b/server/src/inotify.cc @@ -264,10 +264,12 @@ void INotify::addDirectory(std::string name, depth_t depth, uint32_t mask)      struct dirent *dirent;      while( (dirent = readdir(dir)) != NULL ) { -      if(std::string(dirent->d_name) == "." || std::string(dirent->d_name) == "..") +      if(std::string(dirent->d_name) == "." || +         std::string(dirent->d_name) == "..")          continue; -      if(isdir(name+"/"+dirent->d_name)) addDirectory(name+"/"+dirent->d_name, depth, mask); +      if(isdir(name+"/"+dirent->d_name)) +        addDirectory(name+"/"+dirent->d_name, depth, mask);      }      closedir(dir); @@ -348,7 +350,8 @@ void INotify::readEvents()        addDirectory(dirmap[event->wd].name + "/" + event->name,                     dirmap[event->wd].depth, dirmap[event->wd].mask); -    if(TEST(event->mask, IN_CREATE) && !TEST(dirmap[event->wd].mask, IN_CREATE)) { +    if(TEST(event->mask, IN_CREATE) && +       !TEST(dirmap[event->wd].mask, IN_CREATE)) {        // Ignore this event, it was not requested by the user.      } else {        eventlist.push_back(INotify::Event(event, dirmap[event->wd].name)); diff --git a/server/src/luaresume.cc b/server/src/luaresume.cc index 8ba5641..099c3bd 100644 --- a/server/src/luaresume.cc +++ b/server/src/luaresume.cc @@ -26,6 +26,8 @@   */  #include "luaresume.h" +#include "luautil.h" +  #include "debug.h"  #include <stdio.h> @@ -34,14 +36,9 @@  static int _getValue(lua_State *L)  { -  int n = lua_gettop(L); // number of arguments -  if(n != 1) { -    char errstr[512]; -    sprintf(errstr, "Number of args expected 0, got %d", n); -    lua_pushstring(L, errstr); -    lua_error(L); -    return 1; -  } +  Pracro::checkParameters(L, +                          Pracro::T_STRING, +                          Pracro::T_END);    std::string name = lua_tostring(L, lua_gettop(L)); @@ -65,7 +62,7 @@ LUAResume::LUAResume(Commit &c)  {    L = luaL_newstate();    if(L == NULL) { -    error("Could not create LUA state."); +    PRACRO_ERR(luaresume, "Could not create LUA state.\n");      return;    } @@ -85,7 +82,7 @@ LUAResume::~LUAResume()  std::string LUAResume::getValue(std::string name)  {    if(commit.fields.find(name) == commit.fields.end()) { -    error("LUAResume: No such field '" + name + "'"); +    PRACRO_ERR(luaresume, "LUAResume: No such field '%s'\n", name.c_str());      return "";    } @@ -95,11 +92,11 @@ std::string LUAResume::getValue(std::string name)  std::string LUAResume::run(std::string program)  {    if(L == NULL) { -    error("LUA state not initialized!"); +    PRACRO_ERR(luaresume, "LUA state not initialized!");      return false;    } -  PRACRO_DEBUG(lua, "Running %s\n", program.c_str()); +  PRACRO_DEBUG(luaresume, "Running %s\n", program.c_str());    /*    lua_pushstring(L, value.toStdString().c_str()); @@ -111,24 +108,25 @@ std::string LUAResume::run(std::string program)    int top = lua_gettop(L); -  if(luaL_loadbuffer(L, program.c_str(), program.size(), "lua resume generator")) { -    error(lua_tostring(L, lua_gettop(L))); +  if(luaL_loadbuffer(L, program.c_str(), program.size(), +                     "lua resume generator")) { +    PRACRO_ERR(luaresume, "loadbufer: %s\n", lua_tostring(L, lua_gettop(L)));      return false;    }    // Run the loaded code    if(lua_pcall(L, 0, LUA_MULTRET, 0)) { -    error(lua_tostring(L, lua_gettop(L))); +    PRACRO_ERR(luaresume, "pcall: %s\n" , lua_tostring(L, lua_gettop(L)));      return false;    }    if(top != lua_gettop(L) - 1) { -    error("Program did not return a single value.\n"); +    PRACRO_ERR(luaresume, "Program did not return a single value.\n");      return false;    }    if(lua_isstring(L, lua_gettop(L)) == false) { -    error("Program did not return a string value.\n"); +    PRACRO_ERR(luaresume, "Program did not return a string value.\n");      return false;    } @@ -140,5 +138,5 @@ std::string LUAResume::run(std::string program)  void LUAResume::error(std::string message)  { -  printf("LUA ERROR: %s\n", message.c_str()); +  PRACRO_ERR(luaresume, "LUA ERROR: %s\n", message.c_str());  } diff --git a/server/src/luautil.cc b/server/src/luautil.cc new file mode 100644 index 0000000..116d219 --- /dev/null +++ b/server/src/luautil.cc @@ -0,0 +1,312 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            luautil.cc + * + *  Fri Apr 13 14:38:53 CEST 2007 + *  Copyright 2007 Bent Bisballe Nyeng + *  deva@aasimon.org + ****************************************************************************/ + +/* + *  This file is part of Pracro. + * + *  Pracro is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  Pracro is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with Pracro; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. + */ +#include "luautil.h" + +#include "debug.h" + +#include <string> + +#include <vector> + +std::vector< void * > pointers; + +// for ntohl and htonl +#include <arpa/inet.h> + +#define GLOBAL_PREFIX "magic_global_" + +// +// Get the (somewhat hacky) global pointer to the parser object. +// It is set in the preload method. +// +void *Pracro::getGlobal(lua_State *L, std::string name) +{ +  unsigned int top; +  unsigned int index; + +  std::string var = std::string(GLOBAL_PREFIX) + name; + +  lua_getfield(L, LUA_GLOBALSINDEX, var.c_str());  +  top = lua_gettop(L); +  index = lua_tointeger(L, top); + +  return pointers.at(index); +} + +void Pracro::setGlobal(lua_State *L, std::string name, void *p) +{ +  // Put the value of this in the globals +  char value_of_this[256]; + +  std::string val = std::string(GLOBAL_PREFIX) + name; + +  /* +  unsigned int parser = (unsigned int)p; +  parser = htonl(parser); +  */ + +  pointers.push_back(p); +  unsigned int index = pointers.size() - 1; + +  sprintf(value_of_this, "%s = %u\n", val.c_str(), index); +  int s = luaL_loadstring(L, value_of_this); +  switch(s) { +  case 0: //no errors; +    break; +  case LUA_ERRSYNTAX: //syntax error during pre-compilation; +  case LUA_ERRMEM: //memory allocation error. +    fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L))); +  default: +    fprintf(stderr, "Unknown return value of luaL_loadstring.\n"); +  } + +  // Run program (init) +  s = lua_pcall(L, 0, LUA_MULTRET, 0); +  // Check for errors +  switch(s) { +  case 0: // Success +    break; +  case LUA_ERRRUN:// a runtime error. +  case LUA_ERRMEM:// memory allocation error. +    // For such errors, Lua does not call the error handler function. +  case LUA_ERRERR:// error while running the error handler function. +    fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L))); +    break; +  default: +    fprintf(stderr, "Error: Unknown return value of lua_pcall.\n"); +    break; +  } +} + +void Pracro::call(lua_State *L, std::string function, int numargs) +{ +  // Get function +  lua_getglobal(L, function.c_str()); + +  // Call it +  int s = lua_pcall(L, numargs, LUA_MULTRET, 0); + +  // Check for errors +  switch(s) { +  case 0: // Success +    break; +  case LUA_ERRRUN:// a runtime error. +  case LUA_ERRMEM:// memory allocation error. +    // For such errors, Lua does not call the error handler function. +  case LUA_ERRERR:// error while running the error handler function. +    fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L))); +    break; +  default: +    fprintf(stderr, "Error: Unknown return value of lua_pcall.\n"); +    break; +  } +} + + +/* +lua_isboolean +lua_iscfunction +lua_isfunction +lua_islightuserdata +lua_isnil +lua_isnone +lua_isnoneornil +lua_isnumber +lua_isstring +lua_istable +lua_isthread +lua_isuserdata +*/ +int Pracro::checkParameters(lua_State *L, ...) +{ +  va_list ap; +  va_start(ap, L); + +  size_t nargs = lua_gettop(L); // number of arguments + +  size_t size = 0; +  int t; +  while(1) {  +    t = va_arg(ap, int); +    if(t == T_END) break; + +    switch(t) { +    case T_STRING: +    case T_NUMBER: +    case T_BOOLEAN: +      break; + +    default: +      return luaL_error(L,"Unknown type specifier [%d] at position %d. " +                        "Missing TYPE_END?", t, size+1); +    } + +    size++; +  } + +  va_end(ap); + +  if(nargs != size) { +    return luaL_error(L, "Number of args expected %d, got %d", size, nargs); +  } + +  va_start(ap, L); + +  size_t idx = 0; +  while(1) { +    t = va_arg(ap, int); +    if(t == T_END) break; + +    switch(t) { +    case T_STRING: +      if(lua_isstring(L, lua_gettop(L)-(size-idx-1)) == 0) { +        va_end(ap); +        return luaL_error(L, "Parameter %d should be of type string.", idx+1); +      } +      break; + +    case T_NUMBER: +      if(lua_isnumber(L, lua_gettop(L)-(size-idx-1)) == 0) { +        va_end(ap); +        return luaL_error(L, "Parameter %d should be of type number.", idx+1); +      } +      break; + +    case T_BOOLEAN: +      if(lua_isboolean(L, lua_gettop(L)-(size-idx-1)) == 0) { +        va_end(ap); +        return luaL_error(L, "Parameter %d should be of type boolean.", idx+1); +      } +      break; + +    default: +      va_end(ap); +      return luaL_error(L,"Unknown type specifier [%d] at position %d. " +                        "Missing TYPE_END?", t, idx+1); +    } + +    idx++; +  } + +  va_end(ap); + +  return 0; +} + +#ifdef TEST_LUAUTIL +//deps: +//cflags: $(LUA_CFLAGS) -I.. +//libs: $(LUA_LIBS) +#include "test.h" + +#define LUAPROG \ +  "testfunc('a string', 42, true)" + +#define LUAPROG_BAD1 \ +  "testfunc('a string', 42)" + +#define LUAPROG_BAD2 \ +  "testfunc('a string', 42, true, 'another one')" + +#define LUAPROG_BAD3 \ +  "testfunc(false, 42, 'string')" + +#define LUAPROG_MISSING_END \ +  "testfunc_bad('a string', 42, true, 1)" + +static int testfunc(lua_State *L) +{ +  Pracro::checkParameters(L, +                          Pracro::T_STRING, +                          Pracro::T_NUMBER, +                          Pracro::T_BOOLEAN, +                          Pracro::T_END); +  return 0; +} + +static int testfunc_bad(lua_State *L) +{ +  Pracro::checkParameters(L, +                          Pracro::T_STRING, +                          Pracro::T_NUMBER, +                          Pracro::T_BOOLEAN, +                          Pracro::T_NUMBER); +  return 0; +} + + +TEST_BEGIN; + +int a, b, c; + +lua_State *L; +L = luaL_newstate(); +if(L == NULL) TEST_FATAL("Could not allocate lua state."); +luaL_openlibs(L); + +Pracro::setGlobal(L, "a", &a); +Pracro::setGlobal(L, "b", &b); +Pracro::setGlobal(L, "c", &c); + +TEST_EQUAL(Pracro::getGlobal(L, "b"), &b, "Test get global"); +TEST_EQUAL(Pracro::getGlobal(L, "c"), &c, "Test get global"); +TEST_EQUAL(Pracro::getGlobal(L, "a"), &a, "Test get global"); + +lua_register(L, "testfunc", testfunc); + +if(luaL_loadstring(L, LUAPROG)) { +  TEST_FATAL(lua_tostring(L, lua_gettop(L))) +} +TEST_EQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Good one"); + +if(luaL_loadstring(L, LUAPROG_BAD1)) { +  TEST_FATAL(lua_tostring(L, lua_gettop(L))) +} +TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Too short one"); + +if(luaL_loadstring(L, LUAPROG_BAD2)) { +  TEST_FATAL(lua_tostring(L, lua_gettop(L))) +} +TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Too long one"); + +if(luaL_loadstring(L, LUAPROG_BAD3)) { +  TEST_FATAL(lua_tostring(L, lua_gettop(L))) +} +TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Plain wrong"); + + +lua_register(L, "testfunc_bad", testfunc_bad); +if(luaL_loadstring(L, LUAPROG_MISSING_END)) { +  TEST_FATAL(lua_tostring(L, lua_gettop(L))) +} +TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Missing T_END"); + +lua_close(L); + +TEST_END; + +#endif/*TEST_LUAUTIL*/ diff --git a/server/src/luautil.h b/server/src/luautil.h new file mode 100644 index 0000000..ebbba45 --- /dev/null +++ b/server/src/luautil.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            luautil.h + * + *  Fri Apr 13 14:38:53 CEST 2007 + *  Copyright 2007 Bent Bisballe Nyeng + *  deva@aasimon.org + ****************************************************************************/ + +/* + *  This file is part of Pracro. + * + *  Pracro is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  Pracro is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with Pracro; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. + */ +#ifndef __PRACRO_LUAUTIL_H__ +#define __PRACRO_LUAUTIL_H__ + +#include <lua.hpp> +#include <lauxlib.h> + +#include <string> + +namespace Pracro { + +  /** +   * Set a global pointer that can be reaced from the cFunctions at a later time, +   * using the getGlobal function. +   * @param L The lua_State (active program) from which to get the pointer. +   * @param name The symbolic name in which to store the pointer. +   * @param p The pointer to set. +   */ +  void setGlobal(lua_State *L, std::string name, void *p); +   +  /** +   * Get a global pointer set by the setGlobal function. +   * @param L The lua_State (active program) in which to set the pointer. +   * @param name The symbolic name in which the pointer is stored. +   * @return The pointer. +   */ +  void *getGlobal(lua_State *L, std::string name); +   +  /** +   * Call a function in a lua program. +   * @param L The lua_State (active program) in which to set the function resides. +   * @param function The name of the function to be called. +   */ +  void call(lua_State *L, std::string function, int numargs = 0); + +  typedef enum { +    T_STRING, +    T_NUMBER, +    T_BOOLEAN, +    T_END +  } types_t; +   +  /** +   * Check parameter types and number. +   * @param L The lua_State (active program) in which to set the function resides. +   * @param types The type list (c-vector), describing the required types +   * on the stack. The last type must be a terminating T_END. +   * @return 0 on success. On error a long jump is made through lua_error, thus +   * the function never returns. +   */ +  //  int checkParameters(lua_State *L, types_t types[]); +  int checkParameters(lua_State *L, ...); + +}; + +#endif/*__PRACRO_LUAUTIL_H__*/ diff --git a/server/src/macrolist.cc b/server/src/macrolist.cc index 954149a..908de1e 100644 --- a/server/src/macrolist.cc +++ b/server/src/macrolist.cc @@ -42,6 +42,11 @@ MacroList::MacroList(std::string path)  void MacroList::addFile(std::string file)  { +  if(file.substr(file.size() - 4) != ".xml") { +    PRACRO_DEBUG(macrolist, "Skipping file: %s\n", file.c_str()); +    return; +  } +    PRACRO_DEBUG(macrolist, "Adding file: %s\n", file.c_str());    MacroHeaderParser parser(file);    try { diff --git a/server/src/saxparser.cc b/server/src/saxparser.cc index fcdf4fa..f26c965 100644 --- a/server/src/saxparser.cc +++ b/server/src/saxparser.cc @@ -103,7 +103,8 @@ int SAXParser::parse()    do {      len = readData(buf, sizeof(buf) - 1);      if (! XML_Parse(p, buf, len, len == 0)) { -      parseError(buf, len, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p)); +      parseError(buf, len, XML_ErrorString(XML_GetErrorCode(p)), +                 (int)XML_GetCurrentLineNumber(p));        return 1;      } @@ -123,35 +124,43 @@ static bool iswhitespace(const char *buf, size_t size)  bool SAXParser::parse(const char *data, size_t size)  { -  PRACRO_DEBUG(sax, "parse %d bytes\n", size); +  std::string xml; +  xml.append(data, size); +  PRACRO_DEBUG(sax, "parse %d bytes [%s]\n", size, xml.c_str());    bufferbytes = size;    totalbytes += bufferbytes;    if(! XML_Parse(p, data, size, false) ) {      if(XML_GetErrorCode(p) == XML_ERROR_JUNK_AFTER_DOC_ELEMENT) return true; -    if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && iswhitespace(data, size)) return true; +    if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && +       iswhitespace(data, size)) return true;      if(done && XML_GetErrorCode(p) == XML_ERROR_UNCLOSED_TOKEN) return true; -    parseError(data, size, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p)); +    parseError(data, size, XML_ErrorString(XML_GetErrorCode(p)), +               (int)XML_GetCurrentLineNumber(p));      return false;    }    if(done) {      if(! XML_Parse(p, data, 0, true) ) {        if(XML_GetErrorCode(p) == XML_ERROR_JUNK_AFTER_DOC_ELEMENT) return true; -      if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && iswhitespace(data, size)) return true; +      if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && +         iswhitespace(data, size)) return true;        if(XML_GetErrorCode(p) == XML_ERROR_UNCLOSED_TOKEN) return true; -      parseError(data, 0, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p)); +      parseError(data, 0, XML_ErrorString(XML_GetErrorCode(p)), +                 (int)XML_GetCurrentLineNumber(p));        return false;      }    } -  if(done) PRACRO_DEBUG(sax, "Got END_OF_DOCUMENT [%s] at %ld\n", outertag.c_str(), XML_GetCurrentByteIndex(p)); +  if(done) PRACRO_DEBUG(sax, "Got END_OF_DOCUMENT [%s] at %ld\n", +                        outertag.c_str(), XML_GetCurrentByteIndex(p));    return done;  } -void SAXParser::parseError(const char *buf, size_t len, std::string error, int lineno) +void SAXParser::parseError(const char *buf, size_t len, +                           std::string error, int lineno)  {    fprintf(stderr, "SAXParser error at line %d: %s\n", lineno, error.c_str());    fprintf(stderr, "\tBuffer %u bytes: [", len); diff --git a/server/src/server.cc b/server/src/server.cc index 84c3463..4283a11 100644 --- a/server/src/server.cc +++ b/server/src/server.cc @@ -61,18 +61,18 @@ static std::string error_box(std::string message)    return errorbox;  } -static std::string handleConnection(const char *buf, size_t size, +static std::string handleConnection(const std::string &data,                                      Environment &env, -                                    char **sessionid, -                                    const char *sessioncommit) +                                    std::string &sessionid, +                                    bool sessioncommit)  {    std::string res;    Session *session = NULL; -  if(*sessionid == NULL) { +  if(sessionid == "") {      session = env.sessions.newSession();    } else { -    session = env.sessions.session(*sessionid); +    session = env.sessions.session(sessionid);      if(session == NULL) session = env.sessions.newSession();    } @@ -81,51 +81,44 @@ static std::string handleConnection(const char *buf, size_t size,      return error_box(xml_encode("New session could not be created."));    } -  session->lock(); +  sessionid = session->id(); -  if(asprintf(sessionid, "%s", session->id().c_str()) == -1) *sessionid = NULL; +  { +    SessionAutolock lock(*session); -  Transaction transaction; -  TransactionParser parser(&transaction); +    if(data.length()) { +      Transaction transaction; +      TransactionParser parser(&transaction); +       +      if(!parser.parse(data.c_str(), data.length())) { +        PRACRO_ERR(server, "Failed to parse data!\n"); +        PRACRO_ERR(server, "DATA:[[%s]]\n", data.c_str()); +        res = error_box(xml_encode("XML Parse error.")); +      } else { +        res = handleTransaction(transaction, env, *session); +      } +    } -  if(!parser.parse(buf, size)) { -    PRACRO_ERR(server, "Failed to parse data!\n"); -    res = error_box(xml_encode("XML Parse error.")); -  } else { -    res = handleTransaction(transaction, env, *session);    } -  session->unlock(); - -  if(sessioncommit != NULL) { +  if(sessioncommit) {      session->commit();      env.sessions.deleteSession(session->id());    }    return res; +} -  /* -  Transaction transaction; -  TransactionParser parser(&transaction); -   -  PRACRO_DEBUG(server, "Read %d bytes from network\n", size); - -  std::string res; -  if(size) { -    if(parser.parse(buf, size)) { -      PRACRO_DEBUG(server, "Got complete XML document, %d bytes in current buffer.\n", size); -       -      res = handleTransaction(&transaction, pentominos_socket, -                              *conn->db, session, macrolist, templatelist); -    } else { -      PRACRO_ERR(server, "Failed to parse data!\n"); -      res = error_box(xml_encode("XML Parse error.")); -    } -  } -  return res; +struct condata { +  std::map<std::string, std::string> headers; +  std::string data; +  size_t data_size; +  std::string url; +  std::string method; +  std::string version; +}; -  */ -} +//static std::map<struct MHD_Connection *, struct condata> condata;  static int handle_request_callback(void *cls,                                     struct MHD_Connection *con, @@ -134,40 +127,116 @@ static int handle_request_callback(void *cls,                                     const char *version,                                     const char *data,                                     unsigned int *data_size, -                                   void **ptr) +                                   void **con_cls)  { -  Environment *env = (Environment *)cls; +  PRACRO_DEBUG(httpd, "handle_request_callback con:%p condata:%p\n", +               con, *con_cls); + +  // Test for new connection +  if(*con_cls == NULL) { +    PRACRO_DEBUG(httpd, +                 "handle_request(url=\"%s\", method=\"%s\"," +                 " version=\"%s\", data_size=\"%d\")\n", +                 url, method, version, *data_size); + +    struct condata *cd = new struct condata; +    cd->url = url; +    cd->method = method; +    cd->version = version; +    cd->data_size = 0; +    cd->data = ""; + +    const char *sid = MHD_lookup_connection_value(con, MHD_HEADER_KIND, +                                                  "SessionID"); +    if(sid) cd->headers["SessionID"] = sid; + +    const char *scm = MHD_lookup_connection_value(con, MHD_HEADER_KIND, +                                                  "SessionCommit"); +    if(scm) cd->headers["SessionCommit"] = scm; + +    const char *csz = MHD_lookup_connection_value(con, MHD_HEADER_KIND, +                                                  "Content-Length"); +    if(csz) { +      cd->headers["Content-Length"] = csz; +      cd->data_size = atol(csz); +      PRACRO_DEBUG(httpd, "Content-Length: %s (%d)\n", csz, cd->data_size); +    } -  PRACRO_DEBUG(httpd, -               "handle_request(url=\"%s\", method=\"%s\"," -               " version=\"%s\", data_size=\"%d\")\n", -               url, method, version, *data_size); +    *con_cls = cd; +  } -  const char *sessionid = -    MHD_lookup_connection_value(con, MHD_HEADER_KIND, "SessionID"); -  const char *sessioncommit = -    MHD_lookup_connection_value(con, MHD_HEADER_KIND, "SessionCommit"); +  struct condata *cd = (struct condata*)*con_cls; +  cd->data.append(data, *data_size); -  std::string reply = -    handleConnection(data, *data_size, *env, (char**)&sessionid, sessioncommit); -   -  struct MHD_Response *rsp = -    MHD_create_response_from_data(reply.length(), (char*)reply.c_str(), MHD_NO, MHD_YES); -  MHD_add_response_header(rsp, MHD_HTTP_HEADER_CONTENT_TYPE, "text/plain; charset=UTF-8"); +  int ret = MHD_YES; -  if(*sessionid) { -    MHD_add_response_header(rsp, "SessionID", sessionid); -    free((char*)sessionid); -  } +  PRACRO_DEBUG(httpd, "Waiting for %d bytes of data. Got %d (total %d)\n", +               cd->data_size, *data_size, cd->data.length()); + +  if(cd->data.length() >= cd->data_size) { + +    Environment *env = (Environment *)cls; + +    const char *sid = MHD_lookup_connection_value(con, MHD_HEADER_KIND, +                                                  "SessionID"); +    std::string sessionid; +    if(sid) sessionid = sid; +     +    const char *sessioncommit = +      MHD_lookup_connection_value(con, MHD_HEADER_KIND, "SessionCommit"); +     +    PRACRO_DEBUG(httpd, "Starting to handle SessionID: %s%s\n", +                 sessionid.c_str(), +                 sessioncommit != NULL?" COMMIT":""); +     +    PRACRO_DEBUG(httpd, "Data: [%s]\n", cd->data.c_str()); +     +    std::string reply = +      handleConnection(cd->data, *env, sessionid, sessioncommit != NULL); +     +    struct MHD_Response *rsp = +      MHD_create_response_from_data(reply.length(), (char*)reply.c_str(), +                                    MHD_NO, MHD_YES); +    MHD_add_response_header(rsp, MHD_HTTP_HEADER_CONTENT_TYPE, +                            "text/plain; charset=UTF-8"); +     +    if(sessionid != "") { +      MHD_add_response_header(rsp, "SessionID", sessionid.c_str()); +    } +     +    ret = MHD_queue_response(con, MHD_HTTP_OK, rsp); +    MHD_destroy_response(rsp); +     +    PRACRO_DEBUG(httpd, "Finished handling SessionID: %s%s\n", +                 sessionid.c_str(), +                 sessioncommit != NULL?" COMMIT":""); -  int ret = MHD_queue_response(con, MHD_HTTP_OK, rsp); -  MHD_destroy_response(rsp); + +    delete cd; +    *con_cls = NULL; + +  }    *data_size = 0;    return ret;  } +void requestCompletedCallback(void *cls, +                              struct MHD_Connection *con, +                              void **con_cls, +                              enum MHD_RequestTerminationCode toe) +{ +  PRACRO_DEBUG(httpd, "requestCompletedCallback %p\n", con); + +  // If connection was interrupted prematurely delete the content data here. +  if(*con_cls) { +    struct condata *cd = (struct condata*)*con_cls; +    delete cd; +    *con_cls = NULL; +  } +} +  static void httpderr(void *arg, const char *fmt, va_list ap)  {    PRACRO_ERR_VA(server, fmt, ap); @@ -181,7 +250,8 @@ void server()    bool forceshutdown = false;    port_t port = Conf::server_port; -  int flags = MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY; // | MHD_USE_PEDANTIC_CHECKS +  int flags = MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY; +  // | MHD_USE_PEDANTIC_CHECKS  #ifndef WITHOUT_SSL    if(Conf::use_ssl) flags |= MHD_USE_SSL;  #endif @@ -193,7 +263,8 @@ void server()    struct MHD_Daemon *d;    d = MHD_start_daemon(flags, port, NULL, NULL,                         handle_request_callback, &env, -                       MHD_OPTION_NOTIFY_COMPLETED, NULL, NULL, +                       MHD_OPTION_NOTIFY_COMPLETED, +                          requestCompletedCallback, NULL,                         MHD_OPTION_CONNECTION_LIMIT, Conf::connection_limit,  #ifndef WITHOUT_SSL                         MHD_OPTION_HTTPS_MEM_KEY, Conf::ssl_key.c_str(), @@ -246,10 +317,11 @@ char request[] =  int main()  {    Conf::xml_basedir = "../xml/"; -  Conf::server_port = 32100; // Make sure wo don't interrupt an already running server. +  // Make sure wo don't interrupt an already running server. +  Conf::server_port = 32100;    Conf::database_backend = "testdb";    pid_t pid = fork(); -   +    switch(pid) {    case -1: // error      perror("fork() failed!\n"); diff --git a/server/src/session.cc b/server/src/session.cc index 675bf56..74adb32 100644 --- a/server/src/session.cc +++ b/server/src/session.cc @@ -66,7 +66,7 @@ void Session::commit()  JournalWriter *Session::journal()  {    if(_journal == NULL) { -    _journal = +   _journal =        new JournalWriter(Conf::journal_commit_addr, Conf::journal_commit_port);    }    return _journal; @@ -114,6 +114,17 @@ size_t Sessions::size()    return sessions.size();  } +SessionAutolock::SessionAutolock(Session &s) +  : session(s) +{ +  session.lock(); +} + +SessionAutolock::~SessionAutolock() +{ +  session.unlock(); +} +  #ifdef TEST_SESSION  //deps: configuration.cc journalwriter.cc journal_commit.cc mutex.cc debug.cc  //cflags: -I.. $(PTHREAD_CFLAGS) diff --git a/server/src/session.h b/server/src/session.h index 12c831a..48c01d7 100644 --- a/server/src/session.h +++ b/server/src/session.h @@ -90,5 +90,13 @@ private:    std::map<std::string, Session *> sessions;  }; +class SessionAutolock { +public: +  SessionAutolock(Session &session); +  ~SessionAutolock(); + +private: +  Session &session; +};  #endif/*__PRACRO_SESSION_H__*/ diff --git a/server/src/templatelist.cc b/server/src/templatelist.cc index b8e8462..af03586 100644 --- a/server/src/templatelist.cc +++ b/server/src/templatelist.cc @@ -39,6 +39,11 @@ TemplateList::TemplateList(std::string path)  void TemplateList::addFile(std::string file)  { +  if(file.substr(file.size() - 4) != ".xml") { +    PRACRO_DEBUG(templatelist, "Skipping file: %s\n", file.c_str()); +    return; +  } +    PRACRO_DEBUG(templatelist, "Adding file: %s\n", file.c_str());    TemplateHeaderParser parser(file);    try { diff --git a/server/src/transactionhandler.cc b/server/src/transactionhandler.cc index a042a6b..7a45800 100644 --- a/server/src/transactionhandler.cc +++ b/server/src/transactionhandler.cc @@ -48,7 +48,8 @@ static std::string error_box(std::string message)    return errorbox;  } -static std::string handleCommits(Transaction &transaction, Environment &env, Session &session) +static std::string handleCommits(Transaction &transaction, Environment &env, +                                 Session &session)  {    std::string answer; @@ -66,7 +67,8 @@ static std::string handleCommits(Transaction &transaction, Environment &env, Ses        std::string resume = resume_parser(macro->resume, commit);        commit.fields["journal.resume"] = resume; -      db->commitTransaction(transaction.user, transaction.cpr, *macro, commit.fields); +      db->commitTransaction(transaction.user, transaction.cpr, *macro, +                            commit.fields);        if(resume != "") { @@ -84,7 +86,8 @@ static std::string handleCommits(Transaction &transaction, Environment &env, Ses    return answer;  } -static std::string handleRequest(Transaction &transaction, Environment &env, Session &session) +static std::string handleRequest(Transaction &transaction, Environment &env, +                                 Session &session)  {    std::string answer; @@ -120,7 +123,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses          Macro ¯o = (*mi2);          if(macro.isHeader) { -          answer += "    <header caption=\"" + macro.attributes["caption"] + "\"/>\n"; +          answer += "    <header caption=\"" + macro.attributes["caption"] + +            "\"/>\n";            mi2++;            continue;          } @@ -133,7 +137,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses          if(completed) answer += "\"true\"";          else answer += "\"false\""; -        std::map< std::string, std::string >::iterator ai = macro.attributes.begin(); +        std::map< std::string, std::string >::iterator ai = +          macro.attributes.begin();          while(ai != macro.attributes.end()) {            std::string name = ai->first;            std::string value = ai->second; @@ -167,7 +172,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses              if(service == "pentominos") {                // Send the queries to Pentominos (if any) -              QueryHandlerPentominos qh(*atf, transaction.cpr, "pracrod"); +              QueryHandlerPentominos qh(*atf, transaction.cpr, +                                        "pracrod"/*user*/);                QueryResult queryresult = qh.exec(*qi);                lqm.addQueryResult(queryresult); @@ -190,7 +196,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses              std::vector< Script >::iterator spi = m->scripts.begin();              while(spi != m->scripts.end()) { -              answer += "        <script language=\"" + spi->attributes["language"]  +              answer += "        <script language=\"" + +                spi->attributes["language"]                   + "\" name=\"" + spi->attributes["name"] + "\">\n";                answer += xml_encode(spi->attributes["code"]);                answer += "\n        </script>\n"; @@ -212,7 +219,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses          if(completed) {            answer += "      <resume>"; -          answer += db->getResume(transaction.cpr, macro, time(NULL) - Conf::db_max_ttl); +          answer += db->getResume(transaction.cpr, macro, time(NULL) - +                                  Conf::db_max_ttl);            answer += "</resume>\n";          } @@ -233,7 +241,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses    return answer;  } -std::string handleTransaction(Transaction &transaction, Environment &env, Session &session) +std::string handleTransaction(Transaction &transaction, Environment &env, +                              Session &session)  {    std::string answer; diff --git a/server/src/transactionparser.cc b/server/src/transactionparser.cc index f1f79c6..7422a13 100644 --- a/server/src/transactionparser.cc +++ b/server/src/transactionparser.cc @@ -36,31 +36,6 @@  #include "debug.h"  #include "exception.h" -static void error(const char* fmt, ...) -{ -  PRACRO_ERR_LOG(transactionparser, "Error in TransactionParser: "); - -  { -    va_list argp; -    va_start(argp, fmt); -    PRACRO_ERR_LOG_VA(macro, fmt, argp); -    va_end(argp); - -    fprintf(stderr, "\n"); -  } - -  { -    char *p; -    va_list argp; -    va_start(argp, fmt); -    if(vasprintf(&p, fmt, argp) != -1) { -      throw Exception("Error in TransactionParser: " + std::string(p)); -      free(p); -    } -    va_end(argp); -  } -} -  TransactionParser::TransactionParser(Transaction *transaction)  {    this->transaction = transaction; @@ -68,8 +43,11 @@ TransactionParser::TransactionParser(Transaction *transaction)    totalbytes = 0;  } -void TransactionParser::startTag(std::string name, std::map< std::string, std::string> attributes) +void TransactionParser::startTag(std::string name, +                                 std::map<std::string, std::string> attributes)  { +  PRACRO_DEBUG(transactionparser, "<%s>\n", name.c_str()); +    if(name == "pracro") {      transaction->user = attributes["user"];      transaction->cpr = attributes["cpr"]; @@ -92,26 +70,37 @@ void TransactionParser::startTag(std::string name, std::map< std::string, std::s    }    if(name == "field") { -    if(!transaction->commits.size()) error("Field without a commit tag!"); -    if(attributes.find("name") == attributes.end()) error("Field is missing 'name' attribute"); -    if(attributes.find("value") == attributes.end()) error("Field is missing 'value' attribute"); -    transaction->commits.back().fields[attributes["name"]] = attributes["value"]; +    if(!transaction->commits.size()) { +      PRACRO_ERR(transactionparser, "Field without a commit tag!"); +      return; +    } + +    if(attributes.find("name") == attributes.end()) { +      PRACRO_ERR(transactionparser, "Field is missing 'name' attribute"); +      return; +    } + +    if(attributes.find("value") == attributes.end()) { +      PRACRO_ERR(transactionparser, "Field is missing 'value' attribute"); +      return; +    } + +    transaction->commits.back().fields[attributes["name"]] = +      attributes["value"];    }  } -void TransactionParser::parseError(const char *buf, size_t len, std::string error, int lineno) +void TransactionParser::parseError(const char *buf, size_t len, +                                   std::string error, int lineno)  { -  PRACRO_ERR_LOG(transactionparser, "TransactionParser error at line %d: %s\n", -                 lineno, error.c_str()); -  PRACRO_ERR_LOG(transactionparser, "\tBuffer %u bytes: [", len); -  if(fwrite(buf, len, 1, stderr) != len) {} -  PRACRO_ERR_LOG(transactionparser, "]\n"); - -  char *slineno; -  if(asprintf(&slineno, " at line %d\n", lineno) != -1) { -    throw Exception(error + slineno); -    free(slineno); -  } +  PRACRO_ERR(transactionparser, "TransactionParser error at line %d: %s\n", +             lineno, error.c_str()); + +  std::string xml; +  xml.append(buf, len); + +  PRACRO_ERR(transactionparser, "\tBuffer %u bytes: [%s]\n", +             len, xml.c_str());  }  #ifdef TEST_TRANSACTIONPARSER | 
