]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: If we get disconnected, say exactly what the error was.
authorTimo Sirainen <tss@iki.fi>
Tue, 5 Mar 2013 12:32:03 +0000 (14:32 +0200)
committerTimo Sirainen <tss@iki.fi>
Tue, 5 Mar 2013 12:32:03 +0000 (14:32 +0200)
src/lib-http/http-client-connection.c
src/lib-http/http-client-private.h
src/lib-http/http-client-request.c

index e2d5210ce49029af50a86fdc66d026c3b164f6a8..dff148979eba8a9fc0223ea652d089799a6e6727 100644 (file)
@@ -200,6 +200,7 @@ http_client_connection_continue_timeout(struct http_client_connection *conn)
 {
        struct http_client_request *const *req_idx;
        struct http_client_request *req;
+       const char *error;
 
        if (conn->to_response != NULL)
                timeout_remove(&conn->to_response);
@@ -212,18 +213,19 @@ http_client_connection_continue_timeout(struct http_client_connection *conn)
        req = req_idx[0];
 
        conn->payload_continue = TRUE;
-       if (http_client_request_send_more(req) < 0) {
+       if (http_client_request_send_more(req, &error) < 0) {
                http_client_connection_abort_temp_error(&conn,
-                       HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST, "Failed to send request");
+                       HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
+                       t_strdup_printf("Failed to send request: %s", error));
        }
 }
 
 bool http_client_connection_next_request(struct http_client_connection *conn)
 {
        struct http_client_request *req = NULL;
+       const char *error;
 
        if (!http_client_connection_is_ready(conn)) {
-               
                http_client_connection_debug(conn, "Not ready for next request");
                return FALSE;
        }
@@ -250,10 +252,10 @@ bool http_client_connection_next_request(struct http_client_connection *conn)
        http_client_connection_debug(conn, "Claimed request %s",
                http_client_request_label(req));
 
-       if (http_client_request_send(req) < 0) {
+       if (http_client_request_send(req, &error) < 0) {
                http_client_connection_abort_temp_error(&conn,
                        HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
-                       "Failed to send request");
+                       t_strdup_printf("Failed to send request: %s", error));
                return FALSE;
        }
 
@@ -292,8 +294,10 @@ static void http_client_connection_destroy(struct connection *_conn)
                break;
        case CONNECTION_DISCONNECT_CONN_CLOSED:
                /* retry pending requests if possible */
+               errno = _conn->input->stream_errno;
                http_client_connection_retry_requests(conn,
-                       HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST, "Connection lost");
+                       HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
+                       t_strdup_printf("Connection lost: %m"));
        default:
                break;
        }
@@ -459,10 +463,10 @@ static void http_client_connection_input(struct connection *_conn)
                        conn->payload_continue = TRUE;
                        http_client_connection_debug(conn,
                                "Got expected 100-continue response");
-                       if (http_client_request_send_more(req) < 0) {
+                       if (http_client_request_send_more(req, &error) < 0) {
                                http_client_connection_abort_temp_error(&conn,
                                        HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
-                                       "Failed to send request");
+                                       t_strdup_printf("Failed to send request: %s", error));
                        }
                        return;
                } else if (response->status / 100 == 1) {
@@ -523,13 +527,14 @@ static void http_client_connection_input(struct connection *_conn)
        }
 
        if (ret <= 0 &&
-               (conn->conn.input->eof || conn->conn.input->stream_errno != 0)) {
+           (conn->conn.input->eof || conn->conn.input->stream_errno != 0)) {
                int stream_errno = conn->conn.input->stream_errno;
-               http_client_connection_debug(conn,
-                       "Lost connection to server (error=%s)",
-                       stream_errno != 0 ? strerror(stream_errno) : "EOF");
                http_client_connection_abort_temp_error(&conn,
-                       HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST, "Connection lost");
+                       HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
+                       t_strdup_printf("Connection lost: read(%s) failed: %s",
+                                       i_stream_get_name(conn->conn.input),
+                                       stream_errno != 0 ?
+                                       strerror(stream_errno) : "EOF"));
                return;
        }
 
@@ -550,12 +555,15 @@ static int http_client_connection_output(struct http_client_connection *conn)
 {
        struct http_client_request *const *req_idx, *req;
        struct ostream *output = conn->conn.output;
+       const char *error;
        int ret;
 
        if ((ret = o_stream_flush(output)) <= 0) {
                if (ret < 0) {
                        http_client_connection_abort_temp_error(&conn,
-                               HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST, "Connection lost");
+                               HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
+                               t_strdup_printf("Connection lost: write(%s) failed: %m",
+                                               o_stream_get_name(output)));
                }
                return ret;
        }
@@ -565,9 +573,10 @@ static int http_client_connection_output(struct http_client_connection *conn)
                req = req_idx[0];
 
                if (!req->payload_sync || conn->payload_continue) {
-                       if (http_client_request_send_more(req) < 0) {
+                       if (http_client_request_send_more(req, &error) < 0) {
                                http_client_connection_abort_temp_error(&conn,
-                                       HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST, "Connection lost");
+                                       HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
+                                       t_strdup_printf("Connection lost: %s", error));
                                return -1;
                        }
                        if (!conn->output_locked) {
index 9529c227537a09f427bd75c991e716aefe277825..70ce6db49482cb98cb1f0ecdf20624035b3329ec 100644 (file)
@@ -200,8 +200,10 @@ http_client_connection_label(struct http_client_connection *conn)
 
 void http_client_request_ref(struct http_client_request *req);
 void http_client_request_unref(struct http_client_request **_req);
-int http_client_request_send(struct http_client_request *req);
-int http_client_request_send_more(struct http_client_request *req);
+int http_client_request_send(struct http_client_request *req,
+                            const char **error_r);
+int http_client_request_send_more(struct http_client_request *req,
+                                 const char **error_r);
 void http_client_request_callback(struct http_client_request *req,
        struct http_response *response);
 void http_client_request_resubmit(struct http_client_request *req);
index 58fc4eaa9fc6ffe2a48612fd1e7c6f476bd9fe09..4a619280e2ff43c77fe5fd2fe6848362cefda83e 100644 (file)
@@ -215,6 +215,7 @@ http_client_request_continue_payload(struct http_client_request **_req,
                        http_client_request_finish_payload_out(req);
        } else { 
                req->payload_input = i_stream_create_from_data(data, size);
+               i_stream_set_name(req->payload_input, "<HTTP request payload>");
        }
        req->payload_size = 0;
        req->payload_chunked = TRUE;
@@ -275,20 +276,32 @@ int http_client_request_finish_payload(struct http_client_request **_req)
        return http_client_request_continue_payload(_req, NULL, 0);
 }
 
-int http_client_request_send_more(struct http_client_request *req)
+int http_client_request_send_more(struct http_client_request *req,
+                                 const char **error_r)
 {
        struct http_client_connection *conn = req->conn;
        struct ostream *output = req->payload_output;
-       int ret = 0;
+       off_t ret;
 
        i_assert(req->payload_input != NULL);
 
        /* chunked ostream needs to write to the parent stream's buffer */
        o_stream_set_max_buffer_size(output, IO_BLOCK_SIZE);
-       if (o_stream_send_istream(output, req->payload_input) < 0)
-               ret = -1;
+       ret = o_stream_send_istream(output, req->payload_input);
        o_stream_set_max_buffer_size(output, (size_t)-1);
 
+       if (req->payload_input->stream_errno != 0) {
+               errno = req->payload_input->stream_errno;
+               *error_r = t_strdup_printf("read(%s) failed: %m",
+                                          i_stream_get_name(req->payload_input));
+       } else if (output->stream_errno != 0) {
+               errno = output->stream_errno;
+               *error_r = t_strdup_printf("write(%s) failed: %m",
+                                          o_stream_get_name(output));
+       } else {
+               i_assert(ret >= 0);
+       }
+
        if (!i_stream_have_bytes_left(req->payload_input)) {
                if (!req->payload_chunked &&
                        req->payload_input->v_offset - req->payload_offset != req->payload_size) {
@@ -309,10 +322,11 @@ int http_client_request_send_more(struct http_client_request *req)
                o_stream_set_flush_pending(output, TRUE);
                http_client_request_debug(req, "Partially sent payload");
        }
-       return ret;
+       return ret < 0 ? -1 : 0;
 }
 
-int http_client_request_send(struct http_client_request *req)
+int http_client_request_send(struct http_client_request *req,
+                            const char **error_r)
 {
        struct http_client_connection *conn = req->conn;
        struct ostream *output = conn->conn.output;
@@ -356,14 +370,17 @@ int http_client_request_send(struct http_client_request *req)
 
        req->state = HTTP_REQUEST_STATE_PAYLOAD_OUT;
        o_stream_cork(output);
-       if (o_stream_sendv(output, iov, N_ELEMENTS(iov)) < 0)
+       if (o_stream_sendv(output, iov, N_ELEMENTS(iov)) < 0) {
+               *error_r = t_strdup_printf("write(%s) failed: %m",
+                                          o_stream_get_name(output));
                ret = -1;
+       }
 
        http_client_request_debug(req, "Sent header");
 
        if (ret >= 0 && req->payload_output != NULL) {
                if (!req->payload_sync) {
-                       if (http_client_request_send_more(req) < 0)
+                       if (http_client_request_send_more(req, error_r) < 0)
                                ret = -1;
                } else {
                        http_client_request_debug(req, "Waiting for 100-continue");