From 965e43178736e6635cf27410e6d73f4ec0fdced2 Mon Sep 17 00:00:00 2001 From: deva Date: Fri, 7 May 2010 09:31:26 +0000 Subject: LOTS of changes. libmicrohttpd fix for 'chunked' POST handling and LUA parameter checker from Pentominos among other things. --- server/src/server.cc | 200 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 136 insertions(+), 64 deletions(-) (limited to 'server/src/server.cc') 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 headers; + std::string data; + size_t data_size; + std::string url; + std::string method; + std::string version; +}; - */ -} +//static std::map 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"); -- cgit v1.2.3