From 9ec9a98e83076bb339d1d546fa445b2420e5a4fb Mon Sep 17 00:00:00 2001 From: deva Date: Fri, 4 Feb 2011 07:35:10 +0000 Subject: A new connection handling mechanism. --- server/src/client_connection.cc | 395 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 395 insertions(+) create mode 100644 server/src/client_connection.cc (limited to 'server/src/client_connection.cc') diff --git a/server/src/client_connection.cc b/server/src/client_connection.cc new file mode 100644 index 0000000..af70916 --- /dev/null +++ b/server/src/client_connection.cc @@ -0,0 +1,395 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * client_connection.cc + * + * Thu Feb 3 09:33:48 CET 2011 + * Copyright 2011 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 "client_connection.h" + +#include "transactionhandler.h" +#include "xml_encode_decode.h" + +static std::string error_box(std::string message) +{ + std::string errorbox = + "\n" + "\n" + " " + message + "\n" + "\n"; + return errorbox; +} + +#ifdef TEST_CONNECTION +static bool did_commit = false; +#endif + +ClientConnection::Parameters::Parameters() +{ + sessionid = ""; + patientid = ""; + templ = ""; + commit = false; + discard = false; + nocommit = false; +} + +ClientConnection::ClientConnection(Environment &e, Parameters p) + : parms(p), env(e), parser(&transaction) +{ + DEBUG(connection, "[%p] CREATE\n", this); + +#ifdef TEST_CONNECTION + did_commit = false; +#endif + + parser_complete = false; +} + +ClientConnection::~ClientConnection() +{ + DEBUG(connection, "[%p] DESTROY\n", this); +} + +void ClientConnection::nocommit(Session *session) +{ + if(parms.nocommit) { + if(session->isreadonly) { // NoCommit of an empty session discards it. + parms.discard = true; + return; + } + + DEBUG(connection, "NoCommit (%s)\n", session->id().c_str()); + parms.nocommit = false; + session->nocommit(); + } +} + +void ClientConnection::commit(Session *session) +{ + if(parms.commit) { + if(session->isreadonly) { // Commit of an empty session discards it. + parms.discard = true; + return; + } + + DEBUG(connection, "Commit (%s)\n", session->id().c_str()); + std::string sid = session->id(); + session->commit(); + env.sessions.deleteSession(sid); + parms.sessionid = ""; + parms.commit = false; +#ifdef TEST_CONNECTION + did_commit = true; +#endif + } +} + +void ClientConnection::discard(Session *session) +{ + if(parms.discard) { + DEBUG(connection, "Discard (%s)\n", session->id().c_str()); + std::string sid = session->id(); + session->discard(); + env.sessions.deleteSession(sid); + parms.sessionid = ""; + parms.discard = false; + } +} + +bool ClientConnection::handle(const char *data, size_t size) +{ + Session *session = NULL; + try { + if(parms.sessionid == "") { + // Create new session + session = env.sessions.newSession(parms.patientid, + parms.templ); + } else { + // Attach to old session + session = env.sessions.session(parms.sessionid); + + // Session didn't exist - create a new one anyway. + if(session == NULL) { + session = env.sessions.newSession(parms.patientid, + parms.templ); + } + } + } catch(Sessions::SessionAlreadyActive &e) { + ERR(connection, "Session already active.\n"); + parser_complete = true; + response = error_box(xml_encode("Session "+e.sessionid+" already active.")); + return true; + } + + if(session == NULL) { + ERR(connection, "New session could not be created.\n"); + response = error_box(xml_encode("New session could not be created.")); + return true; + } + + parms.sessionid = session->id(); + + try { + + if(!data || !size) { + parser_complete = true; + commit(session); + nocommit(session); + discard(session); + return true; + } + + if(parser.parse(data, size)) { + parser_complete = true; + + { + SessionAutolock lock(*session); + response = handleTransaction(transaction, env, *session); + } + + commit(session); + nocommit(session); + discard(session); + + return true; + } + } catch(...) { + ERR(server, "Failed to parse data!\n"); + response = error_box(xml_encode("XML Parse error.")); + return true; + } + + return false; +} + +std::string ClientConnection::getResponse() +{ + if(parser_complete == false) + return error_box(xml_encode("XML Parser need more data.")); + return response; +} + +headers_t ClientConnection::getHeaders() +{ + headers_t hdrs; + + hdrs["Content-Type"] = "text/plain; charset=UTF-8"; + hdrs["SessionID"] = parms.sessionid; + + return hdrs; +} + +#ifdef TEST_CLIENT_CONNECTION +//deps: debug.cc transactionparser.cc session.cc xml_encode_decode.cc saxparser.cc transactionhandler.cc journal.cc mutex.cc templateparser.cc exception.cc configuration.cc macroparser.cc semaphore.cc entitylist.cc luaquerymapper.cc inotify.cc log.cc queryhandlerpentominos.cc widgetgenerator.cc queryhandlerpracro.cc resumeparser.cc journal_commit.cc versionstr.cc luaresume.cc luautil.cc artefact.cc environment.cc database.cc macrolist.cc templatelist.cc pracrodao.cc templateheaderparser.cc macroheaderparser.cc pracrodaotest.cc pracrodaopgsql.cc +//cflags: -DWITHOUT_DATABASE -DWITHOUT_ARTEFACT -I.. $(LUA_CFLAGS) $(EXPAT_CFLAGS) $(PTHREAD_CFLAGS) $(PQXX_CXXFLAGS) +//libs: $(LUA_LIBS) $(EXPAT_LIBS) $(PTHREAD_LIBS) $(PQXX_LIBS) +#include "test.h" + +static char xml_request[] = +"\n" +"\n" +" \n" +"\n" + ; + +static char xml_commit[] = +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" + ; + +static char xml_commit_p1[] = +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +"\n" + ; + +TEST_BEGIN; + +Environment env; +std::string sid; + +// Without data +{ + ClientConnection con(env, "", false); + TEST_TRUE(con.handle("", 0), "Test handler return value."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + sid = con.getSessionID(); + TEST_NOTEQUAL_STR(sid, "", "Test new session id."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + ClientConnection con(env, sid, false); + TEST_TRUE(con.handle("", 0), "Test handler return value."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_EQUAL_STR(con.getSessionID(), sid, "Test existing session id."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + ClientConnection con(env, sid, true); + TEST_TRUE(con.handle("", 0), "Test handler return value."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_EQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_TRUE(did_commit, "Commit."); +} + +{ + ClientConnection con(env, sid, false); + TEST_TRUE(con.handle("", 0), "Test handler return value."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_NOTEQUAL_STR(con.getSessionID(), sid, "Test new session id."); + TEST_FALSE(did_commit, "No commit."); +} + +// With commit partial data +{ + ClientConnection con(env, "", false); + TEST_FALSE(con.handle(xml_commit_p1, sizeof(xml_commit_p1) - 1), + "Test handler return value."); + sid = con.getSessionID(); + TEST_NOTEQUAL_STR(sid, "", "Test new session id."); + TEST_FALSE(did_commit, "No commit."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_TRUE(con.handle(xml_commit_p2, sizeof(xml_commit_p2) - 1), + "Test handler return value."); + TEST_EQUAL_STR(con.getSessionID(), sid, "Test session id."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_FALSE(did_commit, "No commit."); +} + +// With commit partial data and journal commit +{ + ClientConnection con(env, "", true); + TEST_FALSE(con.handle(xml_commit_p1, sizeof(xml_commit_p1) - 1), + "Test handler return value."); + sid = con.getSessionID(); + TEST_NOTEQUAL_STR(sid, "", "Test new session id."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_FALSE(did_commit, "No commit."); + TEST_TRUE(con.handle(xml_commit_p2, sizeof(xml_commit_p2) - 1), + "Test handler return value."); + TEST_EQUAL_STR(con.getSessionID(), "", "Test session id."); + TEST_TRUE(did_commit, "No commit."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); +} + +// With commit data +{ + ClientConnection con(env, "", false); + TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1), + "Test handler return value."); + sid = con.getSessionID(); + TEST_NOTEQUAL_STR(sid, "", "Test new session id."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + ClientConnection con(env, sid, false); + TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_EQUAL_STR(con.getSessionID(), sid, "Test existing session id."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + ClientConnection con(env, sid, true); + TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_EQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_TRUE(did_commit, "Commit."); +} + +{ + ClientConnection con(env, sid, false); + TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_NOTEQUAL_STR(con.getSessionID(), sid, "Test new session id."); + TEST_FALSE(did_commit, "No commit."); +} + +// With request data +{ + ClientConnection con(env, "", false); + TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + sid = con.getSessionID(); + TEST_NOTEQUAL_STR(sid, "", "Test new session id."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + ClientConnection con(env, sid, false); + TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_EQUAL_STR(con.getSessionID(), sid, "Test existing session id."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + ClientConnection con(env, sid, true); + TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_EQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_TRUE(did_commit, "Commit."); +} + +{ + ClientConnection con(env, sid, false); + TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_NOTEQUAL_STR(con.getSessionID(), sid, "Test new session id."); + TEST_FALSE(did_commit, "No commit."); +} + +TEST_END; + +#endif/*TEST_CLIENT_CONNECTION*/ -- cgit v1.2.3