]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: server: Allow determining at any time whether the connection will be closed...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Tue, 17 Oct 2017 14:04:38 +0000 (16:04 +0200)
committerStephan Bosch <stephan.bosch@dovecot.fi>
Tue, 24 Oct 2017 20:29:18 +0000 (22:29 +0200)
Previously, this was only possible during response submission, which potentially requires making a `close' parameter available for any API function that submits a (failure) response.
This would become very ugly and inflexible.

src/lib-http/http-server-private.h
src/lib-http/http-server-request.c
src/lib-http/http-server-response.c
src/lib-http/http-server.h

index 193babcd1af47c165e140c18a6cdf81f4b254489..94a6ac51b627d4a6c23773d8d4f0155662b45936 100644 (file)
@@ -89,7 +89,6 @@ struct http_server_response {
        bool payload_blocking:1;
        bool payload_direct:1;
        bool payload_corked:1;
-       bool close:1;
        bool submitted:1;
 };
 
@@ -119,6 +118,7 @@ struct http_server_request {
        bool delay_destroy:1;
        bool destroy_pending:1;
        bool failed:1;
+       bool connection_close:1;
 };
 
 struct http_server_connection {
index 8ff55eaf94cfe4d8b907b14ad62381f7312f54c4..23aba2a567fa90bd265fb3425b1d7ce7d6b85dab 100644 (file)
@@ -123,6 +123,13 @@ bool http_server_request_unref(struct http_server_request **_req)
        return FALSE;
 }
 
+void http_server_request_connection_close(struct http_server_request *req,
+       bool close)
+{
+       i_assert(req->state < HTTP_SERVER_REQUEST_STATE_SENT_RESPONSE);
+       req->connection_close = close;
+}
+
 void http_server_request_destroy(struct http_server_request **_req)
 {
        struct http_server_request *req = *_req;
@@ -324,7 +331,7 @@ void http_server_request_finished(struct http_server_request *req)
        conn->stats.response_count++;
 
        if (tunnel_callback == NULL) {
-               if (resp->close) {
+               if (req->connection_close) {
                        http_server_connection_close(&conn,
                                t_strdup_printf("Server closed connection: %u %s",
                                        resp->status, resp->reason));
@@ -376,28 +383,28 @@ http_server_request_create_fail_response(struct http_server_request *req,
 
 static void
 http_server_request_fail_full(struct http_server_request *req,
-       unsigned int status, const char *reason, bool close)
+       unsigned int status, const char *reason)
 {
        struct http_server_response *resp;
 
        req->failed = TRUE;
        resp = http_server_request_create_fail_response(req, status, reason);
-       if (close)
-               http_server_response_submit_close(resp);
-       else
-               http_server_response_submit(resp);
+       http_server_response_submit(resp);
+       if (req->conn->input_broken)
+               req->connection_close = TRUE;
 }
 
 void http_server_request_fail(struct http_server_request *req,
        unsigned int status, const char *reason)
 {
-       http_server_request_fail_full(req, status, reason, FALSE);
+       http_server_request_fail_full(req, status, reason);
 }
 
 void http_server_request_fail_close(struct http_server_request *req,
        unsigned int status, const char *reason)
 {
-       http_server_request_fail_full(req, status, reason, TRUE);
+       http_server_request_connection_close(req, TRUE);
+       http_server_request_fail_full(req, status, reason);
 }
 
 void http_server_request_fail_auth(struct http_server_request *req,
index 8082e56b44c1dedb35381b0a9408f6a9db1bc279..2f2ee7139b80d27c2c5821f55f27f29cf65dc898 100644 (file)
@@ -189,41 +189,38 @@ void http_server_response_add_auth_basic(
        http_server_response_add_auth(resp, &chlng);
 }
 
-static void http_server_response_do_submit(struct http_server_response *resp,
-       bool close)
+static void
+http_server_response_do_submit(struct http_server_response *resp)
 {
+       i_assert(!resp->submitted);
        if (resp->date == (time_t)-1)
                resp->date = ioloop_time;
-       resp->close = close;
        resp->submitted = TRUE;
        http_server_request_submit_response(resp->request);     
 }
 
 void http_server_response_submit(struct http_server_response *resp)
 {
-       i_assert(!resp->submitted);
        http_server_response_debug(resp, "Submitted");
 
-       http_server_response_do_submit(resp, FALSE);
+       http_server_response_do_submit(resp);
 }
 
 void http_server_response_submit_close(struct http_server_response *resp)
 {
-       i_assert(!resp->submitted);
-       http_server_response_debug(resp, "Submitted");
-
-       http_server_response_do_submit(resp, TRUE);
+       http_server_request_connection_close(resp->request, TRUE);
+       http_server_response_submit(resp);
 }
 
 void http_server_response_submit_tunnel(struct http_server_response *resp,
        http_server_tunnel_callback_t callback, void *context)
 {
-       i_assert(!resp->submitted);
        http_server_response_debug(resp, "Started tunnelling");
 
        resp->tunnel_callback = callback;
        resp->tunnel_context = context;
-       http_server_response_do_submit(resp, TRUE);
+       http_server_request_connection_close(resp->request, TRUE);
+       http_server_response_do_submit(resp);
 }
 
 static void
@@ -556,6 +553,7 @@ static int http_server_response_send_real(struct http_server_response *resp,
        string_t *rtext = t_str_new(256);
        struct const_iovec iov[3];
        bool is_head = http_request_method_is(&req->req, "HEAD");
+       bool close = FALSE;
        int ret = 0;
 
        *error_r = NULL;
@@ -590,7 +588,7 @@ static int http_server_response_send_real(struct http_server_response *resp,
                                        resp->payload_output = output;
                                        o_stream_ref(output);
                                        /* connection close marks end of payload */
-                                       resp->close = TRUE;
+                                       close = TRUE;
                                }
                        } else {
                                if (!resp->have_hdr_body_spec)
@@ -638,8 +636,8 @@ static int http_server_response_send_real(struct http_server_response *resp,
                        str_append(rtext, "Content-Length: 0\r\n");
        }
        if (!resp->have_hdr_connection) {
-               bool close = resp->close || req->req.connection_close ||
-                       req->conn->input_broken;
+               close = close || req->req.connection_close ||
+                       req->connection_close || req->conn->input_broken;
                if (close && resp->tunnel_callback == NULL)
                        str_append(rtext, "Connection: close\r\n");
                else if (http_server_request_version_equals(req, 1, 0))
index 76dcf1f8dc55f1e51c8099720960bab6f9b4cdb6..6daf0f500fb0d8893584e860b060727c9c9840ee 100644 (file)
@@ -148,6 +148,11 @@ void http_server_request_ref(struct http_server_request *req);
    references, FALSE if not. */
 bool http_server_request_unref(struct http_server_request **_req);
 
+/* Set flag that determines whether the connection is closed after the
+   request is handled. */
+void http_server_request_connection_close(struct http_server_request *req,
+       bool close);
+
 /* Get the pool for this request. */
 pool_t http_server_request_get_pool(struct http_server_request *req);
 /* Returns the response created for the request with