From a3bcbf01feb4a212d7ef3ff12376df8fcee49f6b Mon Sep 17 00:00:00 2001 From: "roberto@localhost.localdomain" Date: Thu, 27 Aug 2009 12:13:57 +0200 Subject: [PATCH] fixes for invalid packet and cherokee module implementation --- cherokee/admin/ModuleUwsgi.py | 56 +++++ cherokee/handler_uwsgi.c | 404 ++++++++++++++++++++++++++++++++++ cherokee/handler_uwsgi.h | 74 +++++++ cherokee/uwsgi.deps | 1 + uwsgi.c | 16 +- 5 files changed, 545 insertions(+), 6 deletions(-) create mode 100644 cherokee/admin/ModuleUwsgi.py create mode 100644 cherokee/handler_uwsgi.c create mode 100644 cherokee/handler_uwsgi.h create mode 100644 cherokee/uwsgi.deps diff --git a/cherokee/admin/ModuleUwsgi.py b/cherokee/admin/ModuleUwsgi.py new file mode 100644 index 00000000..f85e18c2 --- /dev/null +++ b/cherokee/admin/ModuleUwsgi.py @@ -0,0 +1,56 @@ +from Form import * +from Table import * +from Module import * +from validations import * +from consts import * + +# For gettext +N_ = lambda x: x + +from ModuleCgi import * +from ModuleBalancer import NOTE_BALANCER + +HELPS = [ + ('modules_handlers_uwsgi', "UWSGI") +] + +class ModuleUwsgi (ModuleCgiBase): + PROPERTIES = ModuleCgiBase.PROPERTIES + [ + 'balancer' + ] + + def __init__ (self, cfg, prefix, submit): + ModuleCgiBase.__init__ (self, cfg, prefix, 'uwsgi', submit) + + self.show_script_alias = False + self.show_change_uid = False + self.show_document_root = True + + def _op_render (self): + txt = ModuleCgiBase._op_render (self) + + txt += '

%s

' % (_('UWSGI specific')) + + table = TableProps() + prefix = "%s!balancer" % (self._prefix) + e = self.AddPropOptions_Reload_Module (table, _("Balancer"), prefix, + modules_available(BALANCERS), _(NOTE_BALANCER)) + txt += self.Indent(str(table) + e) + return txt + + def _op_apply_changes (self, uri, post): + # Apply balancer changes + pre = "%s!balancer" % (self._prefix) + + new_balancer = post.pop(pre) + if new_balancer: + self._cfg[pre] = new_balancer + + cfg = self._cfg[pre] + if cfg and cfg.value: + name = cfg.value + props = module_obj_factory (name, self._cfg, pre, self.submit_url) + props._op_apply_changes (uri, post) + + # And CGI changes + return ModuleCgiBase._op_apply_changes (self, uri, post) diff --git a/cherokee/handler_uwsgi.c b/cherokee/handler_uwsgi.c new file mode 100644 index 00000000..d236f63b --- /dev/null +++ b/cherokee/handler_uwsgi.c @@ -0,0 +1,404 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* Cherokee + * + * Authors: + * Alvaro Lopez Ortega + * + * Copyright (C) 2001-2009 Alvaro Lopez Ortega + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "common-internal.h" +#include "handler_uwsgi.h" + +#include "connection.h" +#include "source_interpreter.h" +#include "thread.h" +#include "util.h" +#include "connection-protected.h" +#include "bogotime.h" + +#define ENTRIES "handler,cgi" + +/* Plug-in initialization + */ +CGI_LIB_INIT (uwsgi, http_all_methods); + +/* Methods implementation + */ +static ret_t +props_free (cherokee_handler_uwsgi_props_t *props) +{ + if (props->balancer) + cherokee_balancer_free (props->balancer); + + return cherokee_handler_cgi_base_props_free (PROP_CGI_BASE(props)); +} + +ret_t +cherokee_handler_uwsgi_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props) +{ + ret_t ret; + cherokee_list_t *i; + cherokee_handler_uwsgi_props_t *props; + + /* Instance a new property object + */ + if (*_props == NULL) { + CHEROKEE_NEW_STRUCT (n, handler_uwsgi_props); + + cherokee_handler_cgi_base_props_init_base (PROP_CGI_BASE(n), + MODULE_PROPS_FREE(props_free)); + + n->balancer = NULL; + + *_props = MODULE_PROPS(n); + } + + props = PROP_UWSGI(*_props); + + /* Parse the configuration tree + */ + cherokee_config_node_foreach (i, conf) { + cherokee_config_node_t *subconf = CONFIG_NODE(i); + + if (equal_buf_str (&subconf->key, "balancer")) { + ret = cherokee_balancer_instance (&subconf->val, subconf, srv, &props->balancer); + if (ret != ret_ok) return ret; + } + } + + /* Init base class + */ + ret = cherokee_handler_cgi_base_configure (conf, srv, _props); + if (ret != ret_ok) return ret; + + /* Final checks + */ + if (props->balancer == NULL) { + LOG_CRITICAL_S ("ERROR: UWSGI handler needs a balancer\n"); + return ret_error; + } + + return ret_ok; +} + + +static void +add_env_pair (cherokee_handler_cgi_base_t *cgi_base, + const char *key, int key_len, + const char *val, int val_len) +{ + cherokee_handler_uwsgi_t *uwsgi = HDL_UWSGI(cgi_base); + unsigned short u_key_len = (unsigned short) key_len ; + unsigned short u_val_len = (unsigned short) val_len ; + + + /* 2 bytes for every string (16 bit le) */ + cherokee_buffer_ensure_size (&uwsgi->header, uwsgi->header.len + key_len + val_len + 4); + + /* TODO: force to le if cherokee is big-endian */ + + cherokee_buffer_add (&uwsgi->header, (const char *) &u_key_len, 2); + cherokee_buffer_add (&uwsgi->header, key, key_len); + cherokee_buffer_add (&uwsgi->header, (const char *) &u_val_len, 2); + cherokee_buffer_add (&uwsgi->header, val, val_len); +} + + +static ret_t +read_from_uwsgi (cherokee_handler_cgi_base_t *cgi_base, cherokee_buffer_t *buffer) +{ + ret_t ret; + size_t read = 0; + cherokee_handler_uwsgi_t *uwsgi = HDL_UWSGI(cgi_base); + + ret = cherokee_socket_bufread (&uwsgi->socket, buffer, 4096, &read); + + switch (ret) { + case ret_eagain: + cherokee_thread_deactive_to_polling (HANDLER_THREAD(cgi_base), HANDLER_CONN(cgi_base), + uwsgi->socket.socket, 0, false); + return ret_eagain; + + case ret_ok: + TRACE (ENTRIES, "%d bytes read\n", read); + return ret_ok; + + case ret_eof: + case ret_error: + cgi_base->got_eof = true; + return ret; + + default: + RET_UNKNOWN(ret); + } + + SHOULDNT_HAPPEN; + return ret_error; +} + + +ret_t +cherokee_handler_uwsgi_new (cherokee_handler_t **hdl, void *cnt, cherokee_module_props_t *props) +{ + CHEROKEE_NEW_STRUCT (n, handler_uwsgi); + + /* Init the base class + */ + cherokee_handler_cgi_base_init ( + HDL_CGI_BASE(n), cnt, + PLUGIN_INFO_HANDLER_PTR(uwsgi), + HANDLER_PROPS(props), + add_env_pair, read_from_uwsgi); + + /* Virtual methods + */ + MODULE(n)->init = (handler_func_init_t) cherokee_handler_uwsgi_init; + MODULE(n)->free = (module_func_free_t) cherokee_handler_uwsgi_free; + + /* Virtual methods: implemented by handler_cgi_base + */ + HANDLER(n)->step = (handler_func_step_t) cherokee_handler_cgi_base_step; + HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_cgi_base_add_headers; + + /* Properties + */ + n->post_len = 0; + n->src_ref = NULL; + + cherokee_buffer_init (&n->header); + cherokee_socket_init (&n->socket); + + /* Return the object + */ + *hdl = HANDLER(n); + return ret_ok; +} + + +ret_t +cherokee_handler_uwsgi_free (cherokee_handler_uwsgi_t *hdl) +{ + /* Free the rest of the handler CGI memory + */ + cherokee_handler_cgi_base_free (HDL_CGI_BASE(hdl)); + + /* UWSGI stuff + */ + cherokee_socket_close (&hdl->socket); + cherokee_socket_mrproper (&hdl->socket); + + cherokee_buffer_mrproper (&hdl->header); + + return ret_ok; +} + + +static ret_t +uwsgi_fix_packet (cherokee_buffer_t *buf) +{ + + uwsgi_header uh; + + uh.arg1 = 0 ; + uh.arg2 = 0 ; + uh.env_size = (unsigned short) buf->len ; + + /* TODO: check endianess */ + + cherokee_buffer_ensure_size (buf, buf->len + 4); + cherokee_buffer_prepend (buf, (const char * )&uh, 4); + + return ret_ok; +} + + +static ret_t +build_header (cherokee_handler_uwsgi_t *hdl) +{ + + cherokee_handler_cgi_base_build_envp (HDL_CGI_BASE(hdl), HANDLER_CONN(hdl)); + + return uwsgi_fix_packet (&hdl->header); +} + + + +static ret_t +connect_to_server (cherokee_handler_uwsgi_t *hdl) +{ + ret_t ret; + cherokee_connection_t *conn = HANDLER_CONN(hdl); + cherokee_handler_uwsgi_props_t *props = HANDLER_UWSGI_PROPS(hdl); + + /* Get a reference to the target host + */ + if (hdl->src_ref == NULL) { + ret = cherokee_balancer_dispatch (props->balancer, conn, &hdl->src_ref); + if (ret != ret_ok) + return ret; + } + + /* Try to connect + */ + if (hdl->src_ref->type == source_host) { + ret = cherokee_source_connect_polling (hdl->src_ref, &hdl->socket, conn); + if ((ret == ret_deny) || (ret == ret_error)) + { + cherokee_balancer_report_fail (props->balancer, conn, hdl->src_ref); + } + } else { + ret = cherokee_source_interpreter_connect_polling (SOURCE_INT(hdl->src_ref), + &hdl->socket, conn); + } + + return ret; +} + + +static ret_t +send_header (cherokee_handler_uwsgi_t *hdl) +{ + ret_t ret; + size_t written = 0; + cherokee_connection_t *conn = HANDLER_CONN(hdl); + + ret = cherokee_socket_bufwrite (&hdl->socket, &hdl->header, &written); + if (ret != ret_ok) { + conn->error_code = http_bad_gateway; + return ret; + } + +#if 0 + cherokee_buffer_print_debug (&hdl->header, -1); +#endif + cherokee_buffer_move_to_begin (&hdl->header, written); + + TRACE (ENTRIES, "sent remaining=%d\n", hdl->header.len); + + if (! cherokee_buffer_is_empty (&hdl->header)) + return ret_eagain; + + return ret_ok; +} + + +static ret_t +send_post (cherokee_handler_uwsgi_t *hdl) +{ + ret_t ret; + int e_fd = -1; + int mode = 0; + cherokee_connection_t *conn = HANDLER_CONN(hdl); + + ret = cherokee_post_walk_to_fd (&conn->post, hdl->socket.socket, &e_fd, &mode); + + switch (ret) { + case ret_ok: + break; + case ret_eagain: + if (e_fd != -1) + cherokee_thread_deactive_to_polling (HANDLER_THREAD(hdl), conn, e_fd, mode, false); + return ret_eagain; + default: + conn->error_code = http_bad_gateway; + return ret; + } + + return ret_ok; +} + + +ret_t +cherokee_handler_uwsgi_init (cherokee_handler_uwsgi_t *hdl) +{ + ret_t ret; + cherokee_connection_t *conn = HANDLER_CONN(hdl); + + switch (HDL_CGI_BASE(hdl)->init_phase) { + case hcgi_phase_build_headers: + TRACE (ENTRIES, "Init: %s\n", "begins"); + + /* Extracts PATH_INFO and filename from request uri + */ + ret = cherokee_handler_cgi_base_extract_path (HDL_CGI_BASE(hdl), false); + if (unlikely (ret < ret_ok)) { + conn->error_code = http_internal_error; + return ret_error; + } + + /* Prepare Post + */ + if (! cherokee_post_is_empty (&conn->post)) { + cherokee_post_walk_reset (&conn->post); + cherokee_post_get_len (&conn->post, &hdl->post_len); + } + + /* Build the headers + */ + ret = build_header (hdl); + if (unlikely (ret != ret_ok)) { + conn->error_code = http_internal_error; + return ret_error; + } + + HDL_CGI_BASE(hdl)->init_phase = hcgi_phase_connect; + + case hcgi_phase_connect: + TRACE (ENTRIES, "Init: %s\n", "connect"); + + /* Connect + */ + ret = connect_to_server (hdl); + switch (ret) { + case ret_ok: + break; + case ret_eagain: + return ret_eagain; + case ret_deny: + conn->error_code = http_gateway_timeout; + return ret_error; + default: + conn->error_code = http_service_unavailable; + return ret_error; + } + + HDL_CGI_BASE(hdl)->init_phase = hcgi_phase_send_headers; + + case hcgi_phase_send_headers: + TRACE (ENTRIES, "Init: %s\n", "send_headers"); + + /* Send the header + */ + ret = send_header (hdl); + if (ret != ret_ok) + return ret; + + HDL_CGI_BASE(hdl)->init_phase = hcgi_phase_send_post; + + case hcgi_phase_send_post: + /* Send the Post + */ + if (hdl->post_len > 0) { + return send_post (hdl); + } + break; + } + + return ret_ok; +} diff --git a/cherokee/handler_uwsgi.h b/cherokee/handler_uwsgi.h new file mode 100644 index 00000000..a666ec7b --- /dev/null +++ b/cherokee/handler_uwsgi.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* Cherokee + * + * Authors: + * Alvaro Lopez Ortega + * + * Copyright (C) 2001-2009 Alvaro Lopez Ortega + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef CHEROKEE_HANDLER_UWSGI_H +#define CHEROKEE_HANDLER_UWSGI_H + +#include "common-internal.h" + +#include "handler.h" +#include "buffer.h" +#include "plugin_loader.h" +#include "socket.h" +#include "handler_cgi_base.h" +#include "balancer.h" + +typedef struct __attribute__((packed)) { + unsigned char arg1; + unsigned short env_size; + unsigned char arg2; +} uwsgi_header ; + + +typedef struct { + cherokee_handler_cgi_base_t base; + cherokee_balancer_t *balancer; +} cherokee_handler_uwsgi_props_t; + + +typedef struct { + cherokee_handler_cgi_base_t base; + cherokee_buffer_t header; + cherokee_socket_t socket; + cherokee_source_t *src_ref; + time_t spawned; + off_t post_len; +} cherokee_handler_uwsgi_t; + +#define HDL_UWSGI(x) ((cherokee_handler_uwsgi_t *)(x)) +#define PROP_UWSGI(x) ((cherokee_handler_uwsgi_props_t *)(x)) +#define HANDLER_UWSGI_PROPS(x) (PROP_UWSGI(MODULE(x)->props)) + + +/* Library init function + */ +void PLUGIN_INIT_NAME(uwsgi) (cherokee_plugin_loader_t *loader); + +/* Methods + */ +ret_t cherokee_handler_uwsgi_new (cherokee_handler_t **hdl, void *cnt, cherokee_module_props_t *props); +ret_t cherokee_handler_uwsgi_free (cherokee_handler_uwsgi_t *hdl); +ret_t cherokee_handler_uwsgi_init (cherokee_handler_uwsgi_t *hdl); + +#endif /* CHEROKEE_HANDLER_UWSGI_H */ diff --git a/cherokee/uwsgi.deps b/cherokee/uwsgi.deps new file mode 100644 index 00000000..f73f3093 --- /dev/null +++ b/cherokee/uwsgi.deps @@ -0,0 +1 @@ +file diff --git a/uwsgi.c b/uwsgi.c index 89f04b14..142dd51d 100644 --- a/uwsgi.c +++ b/uwsgi.c @@ -284,13 +284,15 @@ void harakiri() { #endif PyGILState_Ensure(); _myself = PyThreadState_Get(); - fprintf(stderr,"\nF*CK !!! i must kill myself (pid: %d app_id: %d) wi: %p wi->wsgi_harakiri: %p thread_state: %p frame: %p...\n", mypid, wsgi_req.app_id, wi, wi->wsgi_harakiri, _myself, _myself->frame ); + if (wi) { + fprintf(stderr,"\nF*CK !!! i must kill myself (pid: %d app_id: %d) wi: %p wi->wsgi_harakiri: %p thread_state: %p frame: %p...\n", mypid, wsgi_req.app_id, wi, wi->wsgi_harakiri, _myself, _myself->frame ); - if (wi && wi->wsgi_harakiri) { - PyEval_CallObject(wi->wsgi_harakiri, wi->wsgi_args); - if (PyErr_Occurred()) { - PyErr_Print(); - } + if (wi->wsgi_harakiri) { + PyEval_CallObject(wi->wsgi_harakiri, wi->wsgi_args); + if (PyErr_Occurred()) { + PyErr_Print(); + } + } } Py_FatalError("HARAKIRI !\n"); } @@ -967,10 +969,12 @@ int main(int argc, char *argv[]) { rlen = read(wsgi_poll.fd, &wsgi_req, 4) ; if (rlen != 4){ fprintf(stderr,"invalid request header size: %d...skip\n", rlen); + close(wsgi_poll.fd); continue; } if (wsgi_req.size > buffer_size) { fprintf(stderr,"invalid request block size: %d...skip\n", wsgi_req.size); + close(wsgi_poll.fd); continue; }