static void
http_client_connection_continue_timeout(struct http_client_connection *conn)
{
- struct http_client_request *const *req_idx;
+ struct http_client_request *const *wait_reqs;
struct http_client_request *req;
+ unsigned int wait_count;
const char *error;
+ i_assert(conn->pending_request == NULL);
+
if (conn->to_response != NULL)
timeout_remove(&conn->to_response);
conn->peer->no_payload_sync = TRUE;
http_client_connection_debug(conn,
"Expected 100-continue response timed out; sending payload anyway");
- i_assert(array_count(&conn->request_wait_list) > 0);
- req_idx = array_idx(&conn->request_wait_list,
- array_count(&conn->request_wait_list)-1);
- req = req_idx[0];
+ wait_reqs = array_get(&conn->request_wait_list, &wait_count);
+ i_assert(wait_count == 1);
+ req = wait_reqs[wait_count-1];
req->payload_sync_continue = TRUE;
- if (http_client_request_send_more(req, &error) < 0) {
+ if (http_client_request_send_more(req, FALSE, &error) < 0) {
http_client_connection_abort_temp_error(&conn,
HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
t_strdup_printf("Failed to send request: %s", error));
{
struct http_client_request *req = NULL;
const char *error;
- bool have_pending_requests;
+ bool pipelined;
if (!http_client_connection_is_ready(conn)) {
http_client_connection_debug(conn, "Not ready for next request");
}
/* claim request, but no urgent request can be second in line */
- have_pending_requests = array_count(&conn->request_wait_list) > 0 ||
+ pipelined = array_count(&conn->request_wait_list) > 0 ||
conn->pending_request != NULL;
- req = http_client_peer_claim_request(conn->peer, have_pending_requests);
+ req = http_client_peer_claim_request(conn->peer, pipelined);
if (req == NULL)
return 0;
http_client_connection_debug(conn, "Claimed request %s",
http_client_request_label(req));
- if (http_client_request_send(req, &error) < 0) {
+ if (http_client_request_send(req, pipelined, &error) < 0) {
http_client_connection_abort_temp_error(&conn,
HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
t_strdup_printf("Failed to send request: %s", error));
indefinite period before sending the message body.
*/
if (req->payload_sync && !conn->peer->seen_100_response) {
+ i_assert(!pipelined);
i_assert(req->payload_chunked || req->payload_size > 0);
i_assert(conn->to_response == NULL);
conn->to_response = timeout_add(HTTP_CLIENT_CONTINUE_TIMEOUT_MSECS,
timeout_remove(&conn->to_input);
conn->conn.io = io_add_istream(conn->conn.input,
http_client_connection_input, &conn->conn);
+ if (array_count(&conn->request_wait_list) > 0)
+ http_client_connection_start_request_timeout(conn);
}
static void
return;
}
- if (http_client_request_send_more(req, &error) < 0) {
+ if (http_client_request_send_more(req, FALSE, &error) < 0) {
http_client_connection_abort_temp_error(&conn,
HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
t_strdup_printf("Failed to send request: %s", error));
payload_type = http_client_request_get_payload_type(req);
} else {
/* no more requests waiting for the connection */
- http_client_connection_stop_request_timeout(conn);
req = NULL;
payload_type = HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED;
}
reqs = array_get(&conn->request_wait_list, &count);
if (count > 0 && conn->output_locked) {
struct http_client_request *req = reqs[count-1];
+ bool pipelined = (count > 1 || conn->pending_request != NULL);
if (req->state == HTTP_REQUEST_STATE_ABORTED) {
http_client_connection_debug(conn,
}
if (!req->payload_sync || req->payload_sync_continue) {
- if (http_client_request_send_more(req, &error) < 0) {
+ if (http_client_request_send_more(req, pipelined, &error) < 0) {
http_client_connection_abort_temp_error(&conn,
HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
t_strdup_printf("Connection lost: %s", error));
}
int http_client_request_send_more(struct http_client_request *req,
- const char **error_r)
+ bool pipelined, const char **error_r)
{
struct http_client_connection *conn = req->conn;
struct ostream *output = req->payload_output;
if (req->payload_wait) {
/* this chunk of input is finished
(client needs to act; disable timeout) */
+ i_assert(!pipelined);
conn->output_locked = TRUE;
http_client_connection_stop_request_timeout(conn);
if (req->client->ioloop != NULL)
} else if (i_stream_get_data_size(req->payload_input) > 0) {
/* output is blocking (server needs to act; enable timeout) */
conn->output_locked = TRUE;
- http_client_connection_start_request_timeout(conn);
+ if (!pipelined)
+ http_client_connection_start_request_timeout(conn);
o_stream_set_flush_pending(output, TRUE);
http_client_request_debug(req, "Partially sent payload");
} else {
/* input is blocking (client needs to act; disable timeout) */
conn->output_locked = TRUE;
- http_client_connection_stop_request_timeout(conn);
+ if (!pipelined)
+ http_client_connection_stop_request_timeout(conn);
conn->io_req_payload = io_add_istream(req->payload_input,
http_client_request_payload_input, req);
}
}
static int http_client_request_send_real(struct http_client_request *req,
- const char **error_r)
+ bool pipelined, const char **error_r)
{
const struct http_client_settings *set = &req->client->set;
struct http_client_connection *conn = req->conn;
if (req->payload_output != NULL) {
if (!req->payload_sync) {
- if (http_client_request_send_more(req, error_r) < 0)
+ if (http_client_request_send_more
+ (req, pipelined, error_r) < 0)
ret = -1;
} else {
http_client_request_debug(req, "Waiting for 100-continue");
}
} else {
req->state = HTTP_REQUEST_STATE_WAITING;
- http_client_connection_start_request_timeout(req->conn);
+ if (!pipelined)
+ http_client_connection_start_request_timeout(req->conn);
conn->output_locked = FALSE;
}
if (ret >= 0 && o_stream_flush(output) < 0) {
}
int http_client_request_send(struct http_client_request *req,
- const char **error_r)
+ bool pipelined, const char **error_r)
{
char *errstr = NULL;
int ret;
T_BEGIN {
- ret = http_client_request_send_real(req, error_r);
+ ret = http_client_request_send_real(req, pipelined, error_r);
if (ret < 0)
errstr = i_strdup(*error_r);
} T_END;