r9409: fix a problem that volker noticed with web page timeouts causing smbd
authorAndrew Tridgell <tridge@samba.org>
Sat, 20 Aug 2005 04:38:35 +0000 (04:38 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:33:34 +0000 (13:33 -0500)
to crash. This is one of the downsides of the fact that the ejs engine
is not event driven, resulting in the rendering of each web page being
'semi-async'. We need to protect the web context from the timeout
processing until we have unwound the stack back to the point that the
'web' variable representing the page rendering logic won't be used any
more.

source/web_server/http.c
source/web_server/web_server.c

index 7bb45afc1e5d549107e8f0b0ea79149062d8e7b2..7aa99b09f67b387f25d2680d717076daa75392ea 100644 (file)
@@ -501,6 +501,7 @@ static void esp_request(struct esp_state *esp, const char *url)
                return;
        }
 #endif
+
        res = espProcessRequest(esp->req, url, buf, &emsg);
        if (res != 0 && emsg) {
                http_writeBlock(web, "<pre>", 5);
@@ -866,6 +867,12 @@ void http_process_input(struct websrv_context *web)
                }
        }
 
+       if (web->conn == NULL) {
+               /* the connection has been terminated above us, probably
+                  via a timeout */
+               goto internal_error;
+       }
+
        if (!web->output.output_pending) {
                http_output_headers(web);
                EVENT_FD_WRITEABLE(web->conn->event.fde);
@@ -909,7 +916,9 @@ void http_process_input(struct websrv_context *web)
 internal_error:
        mprSetCtx(esp);
        talloc_free(esp);
-       http_error(web, 500, "Internal server error");
+       if (web->conn != NULL) {
+               http_error(web, 500, "Internal server error");
+       }
        mprSetCtx(save_mpr_ctx);
        ejs_restore_state(ejs_save);
 }
index 4962185526707c4fdf838a0484e2de8e3e291e78..e85c4f20c79cc448d06e6fe06086e1f224b23d5c 100644 (file)
@@ -52,7 +52,11 @@ static void websrv_timeout(struct event_context *event_context,
                           struct timeval t, void *private)
 {
        struct websrv_context *web = talloc_get_type(private, struct websrv_context);
-       stream_terminate_connection(web->conn, "websrv_timeout: timed out");
+       struct stream_connection *conn = web->conn;
+       web->conn = NULL;
+       /* TODO: send a message to any running esp context on this connection
+          to stop running */
+       stream_terminate_connection(conn, "websrv_timeout: timed out"); 
 }
 
 /*
@@ -108,7 +112,17 @@ static void websrv_recv(struct stream_connection *conn, uint16_t flags)
                        web->input.partial.data[web->input.content_length] = 0;
                }
                EVENT_FD_NOT_READABLE(web->conn->event.fde);
+
+               /* the reference/unlink code here is quite subtle. It
+                is needed because the rendering of the web-pages, and
+                in particular the esp/ejs backend, is semi-async.  So
+                we could well end up in the connection timeout code
+                while inside http_process_input(), but we must not
+                destroy the stack variables being used by that
+                rendering process when we handle the timeout. */
+               talloc_reference(web->task, web);
                http_process_input(web);
+               talloc_unlink(web->task, web);
        }
        return;