]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: http-client-connection - Move response pre-checks to http-client-request.c
authorStephan Bosch <stephan.bosch@open-xchange.com>
Thu, 20 May 2021 22:15:26 +0000 (00:15 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 7 Mar 2025 14:56:56 +0000 (14:56 +0000)
src/lib-http/http-client-connection.c
src/lib-http/http-client-private.h
src/lib-http/http-client-request.c

index 41d4d01d01f7b58bfe9ab4eb90326e42d9ec4ee1..c71a8290e9a080b174846df19cfd79e2f35829b8 100644 (file)
@@ -922,32 +922,6 @@ http_client_connection_return_response(struct http_client_connection *conn,
        return FALSE;
 }
 
-static const char *
-http_client_request_add_event_headers(struct http_client_request *req,
-                                     const struct http_response *response)
-{
-       if (req->event_headers == NULL)
-               return "";
-
-       string_t *str = t_str_new(128);
-       for (unsigned int i = 0; req->event_headers[i] != NULL; i++) {
-               const char *hdr_name = req->event_headers[i];
-               const char *value =
-                       http_response_header_get(response, hdr_name);
-
-               if (value == NULL)
-                       continue;
-
-               str_append(str, str_len(str) == 0 ? " (" : ", ");
-               event_add_str(req->event,
-                             t_strconcat("http_hdr_", hdr_name, NULL), value);
-               str_printfa(str, "%s:%s", hdr_name, value);
-       }
-       if (str_len(str) > 0)
-               str_append_c(str, ')');
-       return str_c(str);
-}
-
 static bool
 http_client_connection_handle_response(struct http_client_connection *conn,
                                       struct http_client_request *req,
@@ -1011,6 +985,7 @@ http_client_connection_process_response(struct http_client_connection *conn,
 {
        struct http_client_request *req_ref;
        bool aborted, early = FALSE;
+       int ret;
 
        if (req == NULL) {
                /* Server sent response without any requests in the wait
@@ -1039,38 +1014,10 @@ http_client_connection_process_response(struct http_client_connection *conn,
        /* Got some response; cancel response timeout */
        timeout_remove(&conn->to_response);
 
-       if (resp->status / 100 == 1) {
-               return http_client_request_1xx_response(req, resp);
-       } else if ((!req->payload_sync || req->payload_sync_continue) &&
-                  !req->payload_finished &&
-                  req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT) {
-               /* Got early response from server while we're still sending
-                  request payload. we cannot recover from this reliably, so we
-                  stop sending payload and close the connection once the
-                  response is processed */
-               e_debug(conn->event,
-                       "Got early input from server; "
-                       "request payload not completely sent "
-                       "(will close connection)");
-               o_stream_unset_flush_callback(conn->conn.output);
-               conn->output_broken = early = TRUE;
-       }
-
-       const char *suffix =
-               http_client_request_add_event_headers(req, resp);
-       e_debug(conn->event,
-               "Got %u response for request %s: %s%s "
-               "(took %lld ms + %lld ms in queue)",
-               resp->status, http_client_request_label(req),
-               resp->reason, suffix,
-               timeval_diff_msecs(&req->response_time, &req->sent_time),
-               timeval_diff_msecs(&req->sent_time, &req->submit_time));
-
-       /* Make sure connection output is unlocked if 100-continue failed */
-       if (req->payload_sync && !req->payload_sync_continue) {
-               e_debug(conn->event, "Unlocked output");
-               conn->output_locked = FALSE;
-       }
+       /* Perform response pre-checks */
+       ret = http_client_request_check_response(req, resp, &early);
+       if (ret <= 0)
+               return ret;
 
        /* Remove request from queue */
        array_pop_front(&conn->request_wait_list);
index d83bea5ce78c407210795f7dbf8241fff5d0c913..192011268702e797c38e5e977a82f7604ef85381 100644 (file)
@@ -501,8 +501,9 @@ int http_client_request_send(struct http_client_request *req, bool pipelined);
 int http_client_request_send_more(struct http_client_request *req,
                                  bool pipelined);
 
-int http_client_request_1xx_response(struct http_client_request *req,
-                                    struct http_response *resp);
+int http_client_request_check_response(struct http_client_request *req,
+                                      struct http_response *resp,
+                                      bool *early_r);
 bool http_client_request_callback(struct http_client_request *req,
                                  struct http_response *response);
 void http_client_request_connect_callback(
index b78134899cf747d9a6080e58f6caeb2f695b4c0e..ebb08f8371a4175321a9e56e7f7410278a7ae2b1 100644 (file)
@@ -1561,8 +1561,35 @@ int http_client_request_send(struct http_client_request *req, bool pipelined)
        return ret;
 }
 
-int http_client_request_1xx_response(struct http_client_request *req,
-                                    struct http_response *resp)
+static const char *
+http_client_request_add_event_headers(struct http_client_request *req,
+                                     const struct http_response *response)
+{
+       if (req->event_headers == NULL)
+               return "";
+
+       string_t *str = t_str_new(128);
+       for (unsigned int i = 0; req->event_headers[i] != NULL; i++) {
+               const char *hdr_name = req->event_headers[i];
+               const char *value =
+                       http_response_header_get(response, hdr_name);
+
+               if (value == NULL)
+                       continue;
+
+               str_append(str, str_len(str) == 0 ? " (" : ", ");
+               event_add_str(req->event,
+                             t_strconcat("http_hdr_", hdr_name, NULL), value);
+               str_printfa(str, "%s:%s", hdr_name, value);
+       }
+       if (str_len(str) > 0)
+               str_append_c(str, ')');
+       return str_c(str);
+}
+
+static int
+http_client_request_1xx_response(struct http_client_request *req,
+                                struct http_response *resp)
 {
        struct http_client_connection *conn = req->conn;
 
@@ -1607,6 +1634,44 @@ int http_client_request_1xx_response(struct http_client_request *req,
        return 0;
 }
 
+int http_client_request_check_response(struct http_client_request *req,
+                                      struct http_response *resp,
+                                      bool *early_r)
+{
+       struct http_client_connection *conn = req->conn;
+
+       if (resp->status / 100 == 1)
+               return http_client_request_1xx_response(req, resp);
+       if (!req->payload_sync && !req->payload_finished &&
+           req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT) {
+               /* Got early response from server while we're still sending
+                  request payload. we cannot recover from this reliably, so we
+                  stop sending payload and close the connection once the
+                  response is processed */
+               e_debug(req->event,
+                       "Got early input from server; "
+                       "request payload not completely sent "
+                       "(will close connection)");
+               o_stream_unset_flush_callback(conn->conn.output);
+               conn->output_broken = *early_r = TRUE;
+       }
+
+       const char *suffix =
+               http_client_request_add_event_headers(req, resp);
+       e_debug(req->event,
+               "Got %u response: %s%s (took %lld ms + %lld ms in queue)",
+               resp->status, resp->reason, suffix,
+               timeval_diff_msecs(&req->response_time, &req->sent_time),
+               timeval_diff_msecs(&req->sent_time, &req->submit_time));
+
+       /* Make sure connection output is unlocked if 100-continue failed */
+       if (req->payload_sync && !req->payload_sync_continue) {
+               e_debug(req->event, "Unlocked output");
+               conn->output_locked = FALSE;
+       }
+       return 1;
+}
+
 bool http_client_request_callback(struct http_client_request *req,
                                  struct http_response *response)
 {