http-client-connection.c revision 744c06ab0d4aebf0e35665740ea7b13b57fd2f59
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2013-2016 Dovecot authors, see the included COPYING file */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "lib.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "net.h"
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen#include "str.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "hash.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "llist.h"
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz#include "array.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "ioloop.h"
de5f478d9e7ae7b8e58082e0b30b6ce1f034236aTimo Sirainen#include "istream.h"
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen#include "istream-timeout.h"
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen#include "ostream.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "time-util.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "iostream-rawlog.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "iostream-ssl.h"
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen#include "http-response-parser.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "http-client-private.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen/*
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * Logging
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenstatic inline void
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenhttp_client_connection_debug(struct http_client_connection *conn,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen const char *format, ...) ATTR_FORMAT(2, 3);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
8952d797eca36f997ec36569e783871b597a9216Timo Sirainenstatic inline void
8952d797eca36f997ec36569e783871b597a9216Timo Sirainenhttp_client_connection_debug(struct http_client_connection *conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *format, ...)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen va_list args;
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen if (conn->client->set.debug) {
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen va_start(args, format);
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen i_debug("http-client: conn %s: %s",
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen conn->label, t_strdup_vprintf(format, args));
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen va_end(args);
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen }
01aca4a521410be85e1f39e37c662435d052f48aAki Tuomi}
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen/*
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen * Connection
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen */
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainenstatic void http_client_connection_ready(struct http_client_connection *conn);
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainenstatic void http_client_connection_input(struct connection *_conn);
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainenunsigned int
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainenhttp_client_connection_count_pending(struct http_client_connection *conn)
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen{
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen unsigned int pending_count = array_count(&conn->request_wait_list);
01aca4a521410be85e1f39e37c662435d052f48aAki Tuomi
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen if (conn->in_req_callback || conn->pending_request != NULL)
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen pending_count++;
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen return pending_count;
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen}
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainenbool http_client_connection_is_idle(struct http_client_connection *conn)
8a6afcd8a6d9ed69626add85a7b75105ee3cb6a1Timo Sirainen{
8a6afcd8a6d9ed69626add85a7b75105ee3cb6a1Timo Sirainen return (conn->to_idle != NULL);
8a6afcd8a6d9ed69626add85a7b75105ee3cb6a1Timo Sirainen}
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenstatic void
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenhttp_client_connection_retry_requests(struct http_client_connection *conn,
8a6afcd8a6d9ed69626add85a7b75105ee3cb6a1Timo Sirainen unsigned int status, const char *error)
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen{
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen const struct http_client_settings *set = &conn->client->set;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_request *req, **req_idx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!array_is_created(&conn->request_wait_list))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (set->no_auto_retry) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Aborting pending requests with error");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Retrying pending requests");
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen }
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen array_foreach_modifiable(&conn->request_wait_list, req_idx) {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen req = *req_idx;
14189e0d0af45ddcb888d026bd8d7e4609912ec5Timo Sirainen /* drop reference from connection */
e564ff0581fc44b78badf8da36e68f9f7a27807eTimo Sirainen req->conn = NULL;
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen if (!http_client_request_unref(req_idx))
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen continue;
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen /* retry the request, which may drop it */
8952d797eca36f997ec36569e783871b597a9216Timo Sirainen if (req->state < HTTP_REQUEST_STATE_FINISHED) {
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen if (set->no_auto_retry)
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi http_client_request_error(&req, status, error);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen else
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz http_client_request_retry(req, status, error);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_clear(&conn->request_wait_list);
f0e416aa42058e7ccc0dc6deec0d4f4a19ee6ebeTimo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_server_close(struct http_client_connection **_conn)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *conn = *_conn;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen struct http_client_request *req, **req_idx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen "Server explicitly closed connection");
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen array_foreach_modifiable(&conn->request_wait_list, req_idx) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen req = *req_idx;
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen /* drop reference from connection */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen req->conn = NULL;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (!http_client_request_unref(req_idx))
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen continue;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* resubmit the request, which may drop it */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (req->state < HTTP_REQUEST_STATE_FINISHED)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_request_resubmit(req);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_clear(&conn->request_wait_list);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->client->ioloop != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen io_loop_stop(conn->client->ioloop);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_close(_conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_abort_error(struct http_client_connection **_conn,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen unsigned int status, const char *error)
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen{
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen struct http_client_connection *conn = *_conn;
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen struct http_client_request *req, **req_idx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn, "Aborting connection: %s", error);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen array_foreach_modifiable(&conn->request_wait_list, req_idx) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req = *req_idx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(req->submitted);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* drop reference from connection */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req->conn = NULL;
b6c9cc2bf7517adcc0b9f98696c61bde321900f6Timo Sirainen if (!http_client_request_unref(req_idx))
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen continue;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen /* drop request if not already aborted */
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen http_client_request_error(&req, status, error);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_clear(&conn->request_wait_list);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_close(_conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_abort_any_requests(struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_request *req, **req_idx;
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen
92a7f5f9bf20c0bd1b1ac309d100f9c144e2b127Timo Sirainen if (array_is_created(&conn->request_wait_list)) {
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen array_foreach_modifiable(&conn->request_wait_list, req_idx) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req = *req_idx;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen i_assert(req->submitted);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen /* drop reference from connection */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen req->conn = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!http_client_request_unref(req_idx))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen continue;
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen /* drop request if not already aborted */
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen http_client_request_error(&req,
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_ABORTED,
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen "Aborting");
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen }
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen array_clear(&conn->request_wait_list);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen }
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if (conn->pending_request != NULL) {
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen req = conn->pending_request;
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen /* drop reference from connection */
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen req->conn = NULL;
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if (http_client_request_unref(&conn->pending_request)) {
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen /* drop request if not already aborted */
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen http_client_request_error(&req,
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_ABORTED,
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen "Aborting");
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen }
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen }
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen}
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainenstatic const char *
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainenhttp_client_connection_get_timing_info(struct http_client_connection *conn)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen{
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen struct http_client_request *const *requestp;
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen unsigned int sent_msecs, total_msecs, connected_msecs;
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen string_t *str = t_str_new(64);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if (array_count(&conn->request_wait_list) > 0) {
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen requestp = array_idx(&conn->request_wait_list, 0);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen sent_msecs = timeval_diff_msecs(&ioloop_timeval, &(*requestp)->sent_time);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen total_msecs = timeval_diff_msecs(&ioloop_timeval, &(*requestp)->submit_time);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen str_printfa(str, "Request sent %u.%03u secs ago",
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen sent_msecs/1000, sent_msecs%1000);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if ((*requestp)->attempts > 0) {
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen str_printfa(str, ", %u attempts in %u.%03u secs",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (*requestp)->attempts + 1,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen total_msecs/1000, total_msecs%1000);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen str_append(str, "No requests");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->conn.last_input != 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen str_printfa(str, ", last input %d secs ago",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (int)(ioloop_time - conn->conn.last_input));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen connected_msecs = timeval_diff_msecs(&ioloop_timeval, &conn->connected_timestamp);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen str_printfa(str, ", connected %u.%03u secs ago",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen connected_msecs/1000, connected_msecs%1000);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return str_c(str);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_abort_temp_error(struct http_client_connection **_conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int status, const char *error)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen struct http_client_connection *conn = *_conn;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen const char *sslerr;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (status == HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST &&
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen conn->ssl_iostream != NULL) {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen sslerr = ssl_iostream_get_last_error(conn->ssl_iostream);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (sslerr != NULL) {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen error = t_strdup_printf("%s (last SSL error: %s)",
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen error, sslerr);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen }
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (ssl_iostream_has_handshake_failed(conn->ssl_iostream)) {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen /* this isn't really a "connection lost", but that we
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen don't trust the remote's SSL certificate. don't
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen retry. */
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen http_client_connection_abort_error(_conn,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_BAD_RESPONSE, error);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen error = t_strdup_printf("%s (%s)", error,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_get_timing_info(conn));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Aborting connection with temporary error: %s", error);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_retry_requests(conn, status, error);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_close(_conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint http_client_connection_check_ready(struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int ret;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (conn->in_req_callback) {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen /* this can happen when a nested ioloop is created inside request
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen callback. we currently don't reuse connections that are occupied
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen this way, but theoretically we could, although that would add
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen quite a bit of complexity.
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen */
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen return 0;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen }
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (!conn->connected || conn->output_locked || conn->output_broken ||
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen conn->close_indicated || conn->tunneling ||
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen http_client_connection_count_pending(conn) >=
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->client->set.max_pipelined_requests)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->last_ioloop != NULL && conn->last_ioloop != current_ioloop) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->last_ioloop = current_ioloop;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* Active ioloop is different from what we saw earlier;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen we may have missed a disconnection event on this connection.
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen Verify status by reading from connection. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((ret=i_stream_read(conn->conn.input)) == -1) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int stream_errno = conn->conn.input->stream_errno;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen i_assert(conn->conn.input->stream_errno != 0 || conn->conn.input->eof);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_abort_temp_error(&conn,
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen t_strdup_printf("Connection lost: read(%s) failed: %s",
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen i_stream_get_name(conn->conn.input),
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek stream_errno != 0 ?
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_stream_get_error(conn->conn.input) :
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "EOF"));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 1;
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen}
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainenstatic void
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainenhttp_client_connection_idle_timeout(struct http_client_connection *conn)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen{
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen http_client_connection_debug(conn, "Idle connection timed out");
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* cannot get here unless connection was established at some point */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen i_assert(conn->connect_succeeded);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen http_client_connection_close(&conn);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen}
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainenvoid http_client_connection_check_idle(struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int timeout, count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->connected &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_is_created(&conn->request_wait_list) &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_count(&conn->request_wait_list) == 0 &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen !conn->in_req_callback &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->incoming_payload == NULL &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->client->set.max_idle_time_msecs > 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->to_idle != NULL) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* timeout already set */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->client->ioloop != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen io_loop_stop(conn->client->ioloop);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen count = array_count(&conn->peer->conns);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(count > 0);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen /* set timeout for this connection */
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen if (count > conn->client->set.max_parallel_connections) {
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen /* instant death for (urgent) connections above limit */
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen timeout = 0;
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen } else {
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen unsigned int idle_count = http_client_peer_idle_connections(conn->peer);
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen /* kill duplicate connections quicker;
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen linearly based on the number of connections */
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen i_assert(count >= idle_count + 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout = (conn->client->set.max_parallel_connections - idle_count) *
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (conn->client->set.max_idle_time_msecs /
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->client->set.max_parallel_connections);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "No more requests queued; going idle (timeout = %u msecs)",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->to_idle =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_add(timeout, http_client_connection_idle_timeout, conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* there should be no idle timeout */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(conn->to_idle == NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_request_timeout(struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->conn.input->stream_errno = ETIMEDOUT;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_abort_temp_error(&conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_TIMED_OUT, "Request timed out");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid http_client_connection_start_request_timeout(
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int timeout_msecs = conn->client->set.request_timeout_msecs;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (timeout_msecs == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen else if (conn->to_requests != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_reset(conn->to_requests);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->to_requests = timeout_add(timeout_msecs,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_request_timeout, conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid http_client_connection_reset_request_timeout(
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->to_requests != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_reset(conn->to_requests);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid http_client_connection_stop_request_timeout(
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->to_requests != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_remove(&conn->to_requests);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_continue_timeout(struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_request *const *wait_reqs;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_request *req;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int wait_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *error;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(conn->pending_request == NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->to_response != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_remove(&conn->to_response);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->peer->no_payload_sync = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Expected 100-continue response timed out; sending payload anyway");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen wait_reqs = array_get(&conn->request_wait_list, &wait_count);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(wait_count == 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req = wait_reqs[wait_count-1];
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen req->payload_sync_continue = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (http_client_request_send_more(req, FALSE, &error) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_abort_temp_error(&conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen t_strdup_printf("Failed to send request: %s", error));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint http_client_connection_next_request(struct http_client_connection *conn)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen{
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen struct http_client_request *req = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *error;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bool pipelined;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((ret=http_client_connection_check_ready(conn)) <= 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ret == 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Not ready for next request");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* claim request, but no urgent request can be second in line */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen pipelined = array_count(&conn->request_wait_list) > 0 ||
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->pending_request != NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req = http_client_peer_claim_request(conn->peer, pipelined);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (req == NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(req->state == HTTP_REQUEST_STATE_QUEUED);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->to_idle != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_remove(&conn->to_idle);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req->payload_sync_continue = FALSE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->peer->no_payload_sync)
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen req->payload_sync = FALSE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* add request to wait list and add a reference */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_append(&conn->request_wait_list, &req, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req->conn = conn;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_request_ref(req);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn, "Claimed request %s",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_request_label(req));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (http_client_request_send(req, pipelined, &error) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_abort_temp_error(&conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen t_strdup_printf("Failed to send request: %s", error));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (req->connect_tunnel)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->tunneling = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* RFC 7231, Section 5.1.1: Expect
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o A client that sends a 100-continue expectation is not required to
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen wait for any specific length of time; such a client MAY proceed to
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen send the message body even if it has not yet received a response.
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen Furthermore, since 100 (Continue) responses cannot be sent through
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen an HTTP/1.0 intermediary, such a client SHOULD NOT wait for an
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen indefinite period before sending the message body.
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen */
6ea145a99eeee923602f04d3c9183bbdba6cd190Timo Sirainen if (req->payload_sync && !conn->peer->seen_100_response) {
6ea145a99eeee923602f04d3c9183bbdba6cd190Timo Sirainen i_assert(!pipelined);
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen i_assert(req->payload_chunked || req->payload_size > 0);
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen i_assert(conn->to_response == NULL);
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen conn->to_response = timeout_add(HTTP_CLIENT_CONTINUE_TIMEOUT_MSECS,
8952d797eca36f997ec36569e783871b597a9216Timo Sirainen http_client_connection_continue_timeout, conn);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void http_client_connection_destroy(struct connection *_conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *conn =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (struct http_client_connection *)_conn;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *error;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int msecs;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen switch (_conn->disconnect_reason) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen case CONNECTION_DISCONNECT_CONNECT_TIMEOUT:
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz if (conn->connected_timestamp.tv_sec == 0) {
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz msecs = timeval_diff_msecs(&ioloop_timeval,
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz &conn->connect_start_timestamp);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen error = t_strdup_printf(
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "connect(%s) failed: Connection timed out in %u.%03u secs",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen _conn->name, msecs/1000, msecs%1000);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen msecs = timeval_diff_msecs(&ioloop_timeval,
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen &conn->connected_timestamp);
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen error = t_strdup_printf(
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen "SSL handshaking with %s failed: Connection timed out in %u.%03u secs",
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen _conn->name, msecs/1000, msecs%1000);
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen }
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen http_client_connection_debug(conn, "%s", error);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen http_client_peer_connection_failure(conn->peer, error);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen break;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen case CONNECTION_DISCONNECT_CONN_CLOSED:
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* retry pending requests if possible */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen error = _conn->input == NULL ? "Connection lost" :
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen t_strdup_printf("Connection lost: %s",
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen i_stream_get_error(_conn->input));
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen http_client_connection_debug(conn, "%s", error);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen http_client_connection_retry_requests(conn,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST, error);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen default:
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen break;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen }
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen http_client_connection_close(&conn);
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen}
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenstatic void http_client_payload_finished(struct http_client_connection *conn)
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen{
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen timeout_remove(&conn->to_input);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen conn->conn.io = io_add_istream(conn->conn.input,
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen http_client_connection_input, &conn->conn);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (array_count(&conn->request_wait_list) > 0)
14189e0d0af45ddcb888d026bd8d7e4609912ec5Timo Sirainen http_client_connection_start_request_timeout(conn);
14189e0d0af45ddcb888d026bd8d7e4609912ec5Timo Sirainen}
e564ff0581fc44b78badf8da36e68f9f7a27807eTimo Sirainen
e564ff0581fc44b78badf8da36e68f9f7a27807eTimo Sirainenstatic void
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainenhttp_client_payload_destroyed_timeout(struct http_client_connection *conn)
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen{
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen if (conn->close_indicated) {
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen http_client_connection_server_close(&conn);
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen return;
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen }
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen http_client_connection_input(&conn->conn);
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen}
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen
2599a77a28bde0653fa090802424469904d518eeTimo Sirainenstatic void http_client_payload_destroyed(struct http_client_request *req)
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen{
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen struct http_client_connection *conn = req->conn;
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen i_assert(conn != NULL);
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen i_assert(conn->pending_request == req);
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen i_assert(conn->incoming_payload != NULL);
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen i_assert(conn->conn.io == NULL);
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen
8952d797eca36f997ec36569e783871b597a9216Timo Sirainen http_client_connection_debug(conn,
8952d797eca36f997ec36569e783871b597a9216Timo Sirainen "Response payload stream destroyed (%u ms after initial response)",
8952d797eca36f997ec36569e783871b597a9216Timo Sirainen timeval_diff_msecs(&ioloop_timeval, &req->response_time));
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* caller is allowed to change the socket fd to blocking while reading
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen the payload. make sure here that it's switched back. */
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi net_set_nonblock(conn->conn.fd_in, TRUE);
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi /* drop reference from connection */
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi req->conn = NULL;
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi if (http_client_request_unref(&conn->pending_request)) {
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi /* finish request if not already aborted */
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi http_client_request_finish(req);
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi }
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi conn->incoming_payload = NULL;
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi /* input stream may have pending input. make sure input handler
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen gets called (but don't do it directly, since we get get here
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen somewhere from the API user's code, which we can't really know what
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen state it is in). this call also triggers sending a new request if
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen necessary. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!conn->disconnected) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->to_input = timeout_add_short
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (0, http_client_payload_destroyed_timeout, conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* room for new requests */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (http_client_connection_check_ready(conn) > 0)
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen http_client_peer_trigger_request_handler(conn->peer);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen}
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenstatic bool
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_return_response(
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_request *req,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_response *response)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *tmp_conn;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct istream *payload;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen bool retrying, ret;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen i_assert(!conn->in_req_callback);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen i_assert(conn->incoming_payload == NULL);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen i_assert(conn->pending_request == NULL);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_request_ref(req);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen req->state = HTTP_REQUEST_STATE_GOT_RESPONSE;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (response->payload != NULL) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* wrap the stream to capture the destroy event without destroying the
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen actual payload stream. */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen conn->incoming_payload = response->payload =
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen i_stream_create_timeout(response->payload,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen conn->client->set.request_timeout_msecs);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen i_stream_add_destroy_callback(response->payload,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_payload_destroyed,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen req);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* the callback may add its own I/O, so we need to remove
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen our one before calling it */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen io_remove(&conn->conn.io);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* we've received the request itself, and we can't reset the
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen timeout during the payload reading. */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_connection_stop_request_timeout(conn);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen }
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen conn->in_req_callback = TRUE;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_connection_ref(conn);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen retrying = !http_client_request_callback(req, response);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen tmp_conn = conn;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (!http_client_connection_unref(&tmp_conn) ||
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen conn->disconnected) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* the callback managed to get this connection destroyed */
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen if (!retrying)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_request_finish(req);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_request_unref(&req);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen return FALSE;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen }
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen conn->in_req_callback = FALSE;
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen if (retrying) {
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen /* retrying, don't destroy the request */
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi if (response->payload != NULL) {
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi i_stream_remove_destroy_callback(conn->incoming_payload,
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen http_client_payload_destroyed);
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen i_stream_unref(&conn->incoming_payload);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen conn->conn.io = io_add_istream(conn->conn.input,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_connection_input,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen &conn->conn);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen }
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_request_unref(&req);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen return TRUE;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen }
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_connection_ref(conn);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (response->payload != NULL) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen req->state = HTTP_REQUEST_STATE_PAYLOAD_IN;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen payload = response->payload;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen response->payload = NULL;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen /* maintain request reference while payload is pending */
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen req->conn = conn;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen conn->pending_request = req;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* request is dereferenced in payload destroy callback */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen i_stream_unref(&payload);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (conn->to_input != NULL && conn->conn.input != NULL) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* already finished reading the payload */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_payload_finished(conn);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen }
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen } else {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_request_finish(req);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_request_unref(&req);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen }
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (conn->incoming_payload == NULL && conn->conn.input != NULL) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(conn->conn.io != NULL ||
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->peer->addr.type == HTTP_CLIENT_PEER_ADDR_RAW);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = FALSE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_unref(&conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void http_client_connection_input(struct connection *_conn)
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *conn =
4d8f538565145fd90eae48df5c4f2ed76e51ca78Timo Sirainen (struct http_client_connection *)_conn;
4d8f538565145fd90eae48df5c4f2ed76e51ca78Timo Sirainen struct http_response response;
4d8f538565145fd90eae48df5c4f2ed76e51ca78Timo Sirainen struct http_client_request *const *reqs;
4d8f538565145fd90eae48df5c4f2ed76e51ca78Timo Sirainen struct http_client_request *req = NULL, *req_ref;
4d8f538565145fd90eae48df5c4f2ed76e51ca78Timo Sirainen enum http_response_payload_type payload_type;
4d8f538565145fd90eae48df5c4f2ed76e51ca78Timo Sirainen unsigned int count;
4d8f538565145fd90eae48df5c4f2ed76e51ca78Timo Sirainen int finished = 0, ret;
be59f9ae981dbe4bdd264053e9febd4ea5dad75bTimo Sirainen const char *error;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
f0e416aa42058e7ccc0dc6deec0d4f4a19ee6ebeTimo Sirainen i_assert(conn->incoming_payload == NULL);
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen _conn->last_input = ioloop_time;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen if (conn->ssl_iostream != NULL &&
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen !ssl_iostream_is_handshaked(conn->ssl_iostream)) {
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz /* finish SSL negotiation by reading from input stream */
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz while ((ret=i_stream_read(conn->conn.input)) > 0) {
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen if (ssl_iostream_is_handshaked(conn->ssl_iostream))
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen break;
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen }
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen if (ret < 0) {
e564ff0581fc44b78badf8da36e68f9f7a27807eTimo Sirainen int stream_errno = conn->conn.input->stream_errno;
00bcc83b18793b9ec5e5d264480a88bf78b10b33Timo Sirainen
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen /* failed somehow */
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen i_assert(ret != -2);
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen error = t_strdup_printf(
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen "SSL handshaking with %s failed: "
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi "read(%s) failed: %s",
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi _conn->name,
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi i_stream_get_name(conn->conn.input),
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi stream_errno != 0 ?
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_stream_get_error(conn->conn.input) : "EOF");
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_peer_connection_failure(conn->peer, error);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen http_client_connection_debug(conn, "%s", error);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen http_client_connection_close(&conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!ssl_iostream_is_handshaked(conn->ssl_iostream)) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* not finished */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(ret == 0);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* ready for first request */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_ready(conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen if (conn->to_input != NULL) {
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* We came here from a timeout added by
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen http_client_payload_destroyed(). The IO couldn't be added
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen back immediately in there, because the HTTP API user may
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen still have had its own IO pointed to the same fd. It should
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen be removed by now, so we can add it back. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_payload_finished(conn);
f0e416aa42058e7ccc0dc6deec0d4f4a19ee6ebeTimo Sirainen finished++;
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek }
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* we've seen activity from the server; reset request timeout */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_reset_request_timeout(conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen /* get first waiting request */
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen reqs = array_get(&conn->request_wait_list, &count);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (count > 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req = reqs[0];
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* determine whether to expect a response payload */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen payload_type = http_client_request_get_payload_type(req);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req = NULL;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen payload_type = HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* drop connection with broken output if last possible input was
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen received */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen if (conn->output_broken && (count == 0 ||
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen (count == 1 && req->state == HTTP_REQUEST_STATE_ABORTED))) {
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen http_client_connection_server_close(&conn);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen return;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen }
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen while ((ret=http_response_parse_next
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (conn->http_parser, payload_type, &response, &error)) > 0) {
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen bool aborted, early = FALSE;
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen if (req == NULL) {
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen /* server sent response without any requests in the wait list */
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen if (response.status == 408) {
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen http_client_connection_debug(conn,
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen "Server explicitly closed connection: 408 %s",
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen response.reason);
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen } else {
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen http_client_connection_debug(conn,
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen "Got unexpected input from server: %u %s",
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen response.status, response.reason);
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen }
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen http_client_connection_close(&conn);
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen return;
b6c9cc2bf7517adcc0b9f98696c61bde321900f6Timo Sirainen }
b6c9cc2bf7517adcc0b9f98696c61bde321900f6Timo Sirainen req->response_time = ioloop_timeval;
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen /* Got some response; cancel response timeout */
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen if (conn->to_response != NULL)
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen timeout_remove(&conn->to_response);
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen /* RFC 7231, Section 6.2:
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen A client MUST be able to parse one or more 1xx responses received
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen prior to a final response, even if the client does not expect one. A
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen user agent MAY ignore unexpected 1xx responses.
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen */
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen if (req->payload_sync && response.status == 100) {
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen if (req->payload_sync_continue) {
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen http_client_connection_debug(conn,
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen "Got 100-continue response after timeout");
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen continue;
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen }
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen conn->peer->no_payload_sync = FALSE;
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen conn->peer->seen_100_response = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req->payload_sync_continue = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Got expected 100-continue response");
8952d797eca36f997ec36569e783871b597a9216Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (req->state == HTTP_REQUEST_STATE_ABORTED) {
b457d2ecf97fb52064f9dd563fd4e8065af39dfbTimo Sirainen http_client_connection_debug(conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Request aborted before sending payload was complete.");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_close(&conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
8952d797eca36f997ec36569e783871b597a9216Timo Sirainen if (http_client_request_send_more(req, FALSE, &error) < 0) {
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen http_client_connection_abort_temp_error(&conn,
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen t_strdup_printf("Failed to send request: %s", error));
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen }
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen return;
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen } else if (response.status / 100 == 1) {
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen /* ignore other 1xx for now */
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen http_client_connection_debug(conn,
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen "Got unexpected %u response; ignoring", response.status);
2ccb478c35972517721ce415d81fcbd11a73fad3Timo Sirainen continue;
f0e811f0e306bb20d3da9c26353bdd5669132f29Timo Sirainen } else if (!req->payload_sync &&
f0e811f0e306bb20d3da9c26353bdd5669132f29Timo Sirainen req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT) {
f0e811f0e306bb20d3da9c26353bdd5669132f29Timo Sirainen /* got early response from server while we're still sending request
f0e811f0e306bb20d3da9c26353bdd5669132f29Timo Sirainen payload. we cannot recover from this reliably, so we stop sending
3e8842470a4a17017529d43b39c40a7549c2ecf2Timo Sirainen payload and close the connection once the response is processed */
3e8842470a4a17017529d43b39c40a7549c2ecf2Timo Sirainen http_client_connection_debug(conn,
c69a177207ed18d0f0210347430a60957136bd6cJosef 'Jeff' Sipek "Got early input from server; "
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "request payload not completely sent (will close connection)");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_unset_flush_callback(conn->conn.output);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->output_broken = early = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Got %u response for request %s (took %u ms + %u ms in queue)",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen response.status, http_client_request_label(req),
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeval_diff_msecs(&req->response_time, &req->sent_time),
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeval_diff_msecs(&req->sent_time, &req->submit_time));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
2ccb478c35972517721ce415d81fcbd11a73fad3Timo Sirainen /* make sure connection output is unlocked if 100-continue failed */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen if (req->payload_sync && !req->payload_sync_continue) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn, "Unlocked output");
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen conn->output_locked = FALSE;
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* remove request from queue */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_delete(&conn->request_wait_list, 0, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req->conn = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen aborted = (req->state == HTTP_REQUEST_STATE_ABORTED);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req_ref = req;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!http_client_request_unref(&req_ref)) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(aborted);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
1856c361aad526948d56d8aafd576bca94516b92Timo Sirainen
1856c361aad526948d56d8aafd576bca94516b92Timo Sirainen conn->close_indicated = response.connection_close;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!aborted) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bool handled = FALSE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* response cannot be 2xx if request payload was not completely sent
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (early && response.status / 100 == 2) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen http_client_request_error(&req,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_BAD_RESPONSE,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen "Server responded with success response "
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen "before all payload was sent");
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen http_client_connection_close(&conn);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen return;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen }
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* don't redirect/retry if we're sending data in small
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen blocks via http_client_request_send_payload()
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen and we're not waiting for 100 continue */
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen if (!req->payload_wait ||
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen (req->payload_sync && !req->payload_sync_continue)) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* failed Expect: */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (response.status == 417 && req->payload_sync) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* drop Expect: continue */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen req->payload_sync = FALSE;
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen conn->output_locked = FALSE;
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen conn->peer->no_payload_sync = TRUE;
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen if (http_client_request_try_retry(req))
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen handled = TRUE;
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen /* redirection */
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen } else if (!req->client->set.no_auto_redirect &&
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen response.status / 100 == 3 && response.status != 304 &&
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen response.location != NULL) {
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen /* redirect (possibly after delay) */
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen if (http_client_request_delay_from_response(req, &response) >= 0) {
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen http_client_request_redirect
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen (req, response.status, response.location);
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen handled = TRUE;
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen }
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen /* service unavailable */
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen } else if (response.status == 503) {
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen /* automatically retry after delay if indicated */
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen if ( response.retry_after != (time_t)-1 &&
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen http_client_request_delay_from_response(req, &response) > 0 &&
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen http_client_request_try_retry(req))
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen handled = TRUE;
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen /* request timeout (by server) */
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen } else if (response.status == 408) {
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen /* automatically retry */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (http_client_request_try_retry(req))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen handled = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* connection close is implicit, although server should indicate
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen that explicitly */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen conn->close_indicated = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!handled) {
e401fa68eb1e7761ffd0b747919d44568555efeeTimo Sirainen /* response for application */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!http_client_connection_return_response
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (conn, req, &response))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
e401fa68eb1e7761ffd0b747919d44568555efeeTimo Sirainen }
e401fa68eb1e7761ffd0b747919d44568555efeeTimo Sirainen }
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen
0098ac3b6dcd8ef6ac20f87a8285da201db75a01Timo Sirainen finished++;
0098ac3b6dcd8ef6ac20f87a8285da201db75a01Timo Sirainen
0098ac3b6dcd8ef6ac20f87a8285da201db75a01Timo Sirainen /* server closing connection? */
b8eb3211af2987d6e8f0d416156171fbd74f0737Timo Sirainen if (conn->close_indicated) {
0098ac3b6dcd8ef6ac20f87a8285da201db75a01Timo Sirainen http_client_connection_server_close(&conn);
b8eb3211af2987d6e8f0d416156171fbd74f0737Timo Sirainen return;
5d9ecbcec051b570d29b8f433d6b26d8435236fdTimo Sirainen }
5d9ecbcec051b570d29b8f433d6b26d8435236fdTimo Sirainen
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen /* get next waiting request */
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen reqs = array_get(&conn->request_wait_list, &count);
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen if (count > 0) {
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen req = reqs[0];
2522acb523343dd37bf788747d86d9470fc08025Timo Sirainen
0098ac3b6dcd8ef6ac20f87a8285da201db75a01Timo Sirainen /* determine whether to expect a response payload */
0098ac3b6dcd8ef6ac20f87a8285da201db75a01Timo Sirainen payload_type = http_client_request_get_payload_type(req);
2522acb523343dd37bf788747d86d9470fc08025Timo Sirainen } else {
b394d41ad4da0e2e7b8bfafccf3b4f3e9ac26ad1Timo Sirainen /* no more requests waiting for the connection */
b394d41ad4da0e2e7b8bfafccf3b4f3e9ac26ad1Timo Sirainen req = NULL;
b394d41ad4da0e2e7b8bfafccf3b4f3e9ac26ad1Timo Sirainen payload_type = HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED;
b394d41ad4da0e2e7b8bfafccf3b4f3e9ac26ad1Timo Sirainen }
2522acb523343dd37bf788747d86d9470fc08025Timo Sirainen
2522acb523343dd37bf788747d86d9470fc08025Timo Sirainen /* drop connection with broken output if last possible input was
2522acb523343dd37bf788747d86d9470fc08025Timo Sirainen received */
2522acb523343dd37bf788747d86d9470fc08025Timo Sirainen if (conn->output_broken && (count == 0 ||
2522acb523343dd37bf788747d86d9470fc08025Timo Sirainen (count == 1 && req->state == HTTP_REQUEST_STATE_ABORTED))) {
2522acb523343dd37bf788747d86d9470fc08025Timo Sirainen http_client_connection_server_close(&conn);
b394d41ad4da0e2e7b8bfafccf3b4f3e9ac26ad1Timo Sirainen return;
2522acb523343dd37bf788747d86d9470fc08025Timo Sirainen }
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen }
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (ret <= 0 &&
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen (conn->conn.input->eof || conn->conn.input->stream_errno != 0)) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen int stream_errno = conn->conn.input->stream_errno;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_abort_temp_error(&conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen t_strdup_printf("Connection lost: read(%s) failed: %s",
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen i_stream_get_name(conn->conn.input),
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen stream_errno != 0 ?
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen i_stream_get_error(conn->conn.input) :
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen "EOF"));
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen return;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen }
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (ret < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_abort_error(&conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_BAD_RESPONSE, error);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen if (finished > 0) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* connection still alive after (at least one) request;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen we can pipeline -> mark for subsequent connections */
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn->peer->allows_pipelining = TRUE;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* room for new requests */
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi if (http_client_connection_check_ready(conn) > 0)
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi http_client_peer_trigger_request_handler(conn->peer);
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi }
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen}
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainenint http_client_connection_output(struct http_client_connection *conn)
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen{
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen struct http_client_request *const *reqs;
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen struct ostream *output = conn->conn.output;
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen unsigned int count;
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen const char *error;
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen int ret;
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen /* we've seen activity from the server; reset request timeout */
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen http_client_connection_reset_request_timeout(conn);
214aff73cd9809446bef169b216d6eb5a81079d8Timo Sirainen
214aff73cd9809446bef169b216d6eb5a81079d8Timo Sirainen if ((ret = o_stream_flush(output)) <= 0) {
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen if (ret < 0) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen http_client_connection_abort_temp_error(&conn,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen t_strdup_printf("Connection lost: write(%s) failed: %s",
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen o_stream_get_name(output),
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen o_stream_get_error(output)));
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen }
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen return ret;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen }
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen i_assert(!conn->output_broken);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (conn->ssl_iostream != NULL &&
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen !ssl_iostream_is_handshaked(conn->ssl_iostream))
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen return 1;
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen reqs = array_get(&conn->request_wait_list, &count);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (count > 0 && conn->output_locked) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen struct http_client_request *req = reqs[count-1];
a8a5f2f8ccc134dcc7b61ea48664c3381db4a1aaTimo Sirainen bool pipelined = (count > 1 || conn->pending_request != NULL);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (req->state == HTTP_REQUEST_STATE_ABORTED) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen http_client_connection_debug(conn,
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen "Request aborted before sending payload was complete.");
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen if (count == 1) {
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen http_client_connection_close(&conn);
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen } else {
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen o_stream_unset_flush_callback(output);
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen conn->output_broken = TRUE;
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen }
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen return 1;
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen }
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen if (!req->payload_sync || req->payload_sync_continue) {
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen if (http_client_request_send_more(req, pipelined, &error) < 0) {
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen http_client_connection_abort_temp_error(&conn,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen t_strdup_printf("Connection lost: %s", error));
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen return -1;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen }
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen if (!conn->output_locked) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* room for new requests */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (http_client_connection_check_ready(conn) > 0)
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen http_client_peer_trigger_request_handler(conn->peer);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen }
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen }
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen return 1;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen}
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainenvoid
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainenhttp_client_connection_start_tunnel(struct http_client_connection **_conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_tunnel *tunnel)
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen{
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen struct http_client_connection *conn = *_conn;
de5f478d9e7ae7b8e58082e0b30b6ce1f034236aTimo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(conn->tunneling);
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen /* claim connection streams */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen memset(tunnel, 0, sizeof(*tunnel));
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen tunnel->input = conn->conn.input;
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen tunnel->output = conn->conn.output;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen tunnel->fd_in = conn->conn.fd_in;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen tunnel->fd_out = conn->conn.fd_out;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen /* detach from connection */
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn->conn.input = NULL;
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen conn->conn.output = NULL;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen conn->conn.fd_in = -1;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen conn->conn.fd_out = -1;
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen conn->closing = TRUE;
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen conn->connected = FALSE;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen connection_disconnect(&conn->conn);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen http_client_connection_unref(_conn);
8a6afcd8a6d9ed69626add85a7b75105ee3cb6a1Timo Sirainen}
8a6afcd8a6d9ed69626add85a7b75105ee3cb6a1Timo Sirainen
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainenstatic void
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenhttp_client_connection_ready(struct http_client_connection *conn)
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen{
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen http_client_connection_debug(conn, "Ready for requests");
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen /* connected */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen conn->connected = TRUE;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen conn->last_ioloop = current_ioloop;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen if (conn->to_connect != NULL)
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen timeout_remove(&conn->to_connect);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* indicate connection success */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen conn->connect_succeeded = TRUE;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen http_client_peer_connection_success(conn->peer);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* start raw log */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen if (conn->client->set.rawlog_dir != NULL) {
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen iostream_rawlog_create(conn->client->set.rawlog_dir,
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen &conn->conn.input, &conn->conn.output);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen }
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* direct tunneling connections handle connect requests just by providing a
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen raw connection */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen if (conn->peer->addr.type == HTTP_CLIENT_PEER_ADDR_RAW) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_request *req;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen req = http_client_peer_claim_request(conn->peer, FALSE);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (req != NULL) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_response response;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_request_ref(req);
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen conn->tunneling = TRUE;
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen memset(&response, 0, sizeof(response));
b6c9cc2bf7517adcc0b9f98696c61bde321900f6Timo Sirainen response.status = 200;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen response.reason = "OK";
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (void)http_client_connection_return_response(conn, req, &response);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_request_unref(&req);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen "No raw connect requests pending; closing useless connection");
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen http_client_connection_close(&conn);
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen return;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen }
b6c9cc2bf7517adcc0b9f98696c61bde321900f6Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* start protocol I/O */
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen conn->http_parser = http_response_parser_init
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen (conn->conn.input, &conn->client->set.response_hdr_limits);
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen o_stream_set_flush_callback(conn->conn.output,
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen http_client_connection_output, conn);
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen}
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainenstatic int
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainenhttp_client_connection_ssl_handshaked(const char **error_r, void *context)
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen{
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen struct http_client_connection *conn = context;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen const char *error, *host = conn->peer->addr.a.tcp.https_name;
b6c9cc2bf7517adcc0b9f98696c61bde321900f6Timo Sirainen
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen if (ssl_iostream_check_cert_validity(conn->ssl_iostream, host, &error) == 0)
a2c4998f6e1fe5ea9a2c9bafd678cd4b6b064a0bTimo Sirainen http_client_connection_debug(conn, "SSL handshake successful");
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen else if (conn->client->set.ssl->allow_invalid_cert) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn, "SSL handshake successful, "
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "ignoring invalid certificate: %s", error);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen } else {
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen *error_r = error;
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen return -1;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen }
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainenhttp_client_connection_ssl_init(struct http_client_connection *conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char **error_r)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct ssl_iostream_settings ssl_set;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *error;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(conn->client->ssl_ctx != NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(&ssl_set, 0, sizeof(ssl_set));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!conn->client->set.ssl->allow_invalid_cert) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ssl_set.verbose_invalid_cert = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ssl_set.verify_remote_cert = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->client->set.debug)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn, "Starting SSL handshake");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (io_stream_create_ssl_client(conn->client->ssl_ctx,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->peer->addr.a.tcp.https_name, &ssl_set,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen &conn->conn.input, &conn->conn.output,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen &conn->ssl_iostream, &error) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen *error_r = t_strdup_printf(
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Couldn't initialize SSL client for %s: %s",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->conn.name, error);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ssl_iostream_set_handshake_callback(conn->ssl_iostream,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_ssl_handshaked, conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen *error_r = t_strdup_printf("SSL handshake to %s failed: %s",
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen conn->conn.name, ssl_iostream_get_last_error(conn->ssl_iostream));
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen return -1;
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen }
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ssl_iostream_is_handshaked(conn->ssl_iostream)) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_ready(conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* wait for handshake to complete; connection input handler does the rest
8759c5d294e762fe9c5b7b19f3842b23aaaaf4ebTimo Sirainen by reading from the input stream */
8759c5d294e762fe9c5b7b19f3842b23aaaaf4ebTimo Sirainen o_stream_set_flush_callback(conn->conn.output,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_output, conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_connected(struct connection *_conn, bool success)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *conn =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (struct http_client_connection *)_conn;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const struct http_client_settings *set = &conn->client->set;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *error;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!success) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_peer_connection_failure(conn->peer, t_strdup_printf(
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "connect(%s) failed: %m", _conn->name));
8759c5d294e762fe9c5b7b19f3842b23aaaaf4ebTimo Sirainen } else {
8759c5d294e762fe9c5b7b19f3842b23aaaaf4ebTimo Sirainen conn->connected_timestamp = ioloop_timeval;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn, "Connected");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (void)net_set_tcp_nodelay(_conn->fd_out, TRUE);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (set->socket_send_buffer_size > 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (net_set_send_buffer_size(_conn->fd_out,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen set->socket_send_buffer_size) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("net_set_send_buffer_size(%"PRIuSIZE_T") failed: %m",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen set->socket_send_buffer_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (set->socket_recv_buffer_size > 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (net_set_recv_buffer_size(_conn->fd_in,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen set->socket_recv_buffer_size) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("net_set_recv_buffer_size(%"PRIuSIZE_T") failed: %m",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen set->socket_recv_buffer_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (http_client_peer_addr_is_https(&conn->peer->addr)) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (http_client_connection_ssl_init(conn, &error) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_peer_connection_failure(conn->peer, error);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn, "%s", error);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_close(&conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
8759c5d294e762fe9c5b7b19f3842b23aaaaf4ebTimo Sirainen http_client_connection_ready(conn);
8759c5d294e762fe9c5b7b19f3842b23aaaaf4ebTimo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic const struct connection_settings http_client_connection_set = {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen .input_max_size = (size_t)-1,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen .output_max_size = (size_t)-1,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen .client = TRUE,
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen .delayed_unix_client_connected_callback = TRUE
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen};
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainenstatic const struct connection_vfuncs http_client_connection_vfuncs = {
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen .destroy = http_client_connection_destroy,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen .input = http_client_connection_input,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen .client_connected = http_client_connection_connected
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen};
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainenstruct connection_list *
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_list_init(void)
0cb80fbd739a9a9b3618a5595b34458a0a994d9bTimo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return connection_list_init
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (&http_client_connection_set, &http_client_connection_vfuncs);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainenstatic void
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainenhttp_client_connection_delayed_connect_error(struct http_client_connection *conn)
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen{
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen timeout_remove(&conn->to_input);
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen errno = conn->connect_errno;
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen http_client_connection_connected(&conn->conn, FALSE);
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen http_client_connection_close(&conn);
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen}
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainenstatic void http_client_connect_timeout(struct http_client_connection *conn)
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen{
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen conn->conn.disconnect_reason = CONNECTION_DISCONNECT_CONNECT_TIMEOUT;
344c4411571e25dcf2f974c07c116a6160c77338Timo Sirainen http_client_connection_destroy(&conn->conn);
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen}
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainenstatic void
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainenhttp_client_connection_connect(struct http_client_connection *conn)
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen{
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen unsigned int msecs;
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen conn->connect_start_timestamp = ioloop_timeval;
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen if (connection_client_connect(&conn->conn) < 0) {
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen conn->connect_errno = errno;
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen http_client_connection_debug(conn, "Connect failed: %m");
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen conn->to_input = timeout_add_short(0,
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen http_client_connection_delayed_connect_error, conn);
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen return;
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen }
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen /* don't use connection.h timeout because we want this timeout
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen to include also the SSL handshake */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen msecs = conn->client->set.connect_timeout_msecs;
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen if (msecs == 0)
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen msecs = conn->client->set.request_timeout_msecs;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (msecs > 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->to_connect =
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen timeout_add(msecs, http_client_connect_timeout, conn);
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen }
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen}
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connect_tunnel_timeout(struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen const char *error, *name = http_client_peer_addr2str(&conn->peer->addr);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen unsigned int msecs;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen msecs = timeval_diff_msecs(&ioloop_timeval,
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen &conn->connect_start_timestamp);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen error = t_strdup_printf(
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen "Tunnel connect(%s) failed: "
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen "Connection timed out in %u.%03u secs",
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen name, msecs/1000, msecs%1000);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen http_client_connection_debug(conn, "%s", error);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen http_client_peer_connection_failure(conn->peer, error);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen http_client_connection_close(&conn);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen}
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainenstatic void
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainenhttp_client_connection_tunnel_response(const struct http_response *response,
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_tunnel tunnel;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *name = http_client_peer_addr2str(&conn->peer->addr);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (response->status != 200) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_peer_connection_failure(conn->peer, t_strdup_printf(
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen "Tunnel connect(%s) failed: %d %s", name,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen response->status, response->reason));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->connect_request = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_request_start_tunnel(conn->connect_request, &tunnel);
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen conn->connect_request = NULL;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
37e8420b32a0fa3442c405616980e45beb494104Timo Sirainen connection_init_from_streams
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen (conn->client->conn_list, &conn->conn, name, tunnel.input, tunnel.output);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_stream_unref(&tunnel.input);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_unref(&tunnel.output);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->connect_initialized = TRUE;
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_connect_tunnel(struct http_client_connection *conn,
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen const struct ip_addr *ip, in_port_t port)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int msecs;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->connect_start_timestamp = ioloop_timeval;
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->connect_request = http_client_request_connect_ip
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (conn->client, ip, port, http_client_connection_tunnel_response, conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_request_set_urgent(conn->connect_request);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_request_submit(conn->connect_request);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen /* don't use connection.h timeout because we want this timeout
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen to include also the SSL handshake */
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen msecs = conn->client->set.connect_timeout_msecs;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen if (msecs == 0)
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen msecs = conn->client->set.request_timeout_msecs;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen if (msecs > 0) {
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn->to_connect =
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen timeout_add(msecs, http_client_connect_tunnel_timeout, conn);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen }
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen}
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
b6c9cc2bf7517adcc0b9f98696c61bde321900f6Timo Sirainenstruct http_client_connection *
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainenhttp_client_connection_create(struct http_client_peer *peer)
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen{
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen struct http_client_connection *conn;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen static unsigned int id = 0;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen const struct http_client_peer_addr *addr = &peer->addr;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen const char *conn_type = "UNKNOWN";
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen switch (peer->addr.type) {
b07a3abc4cc692661f5afd2fb654acb687884613Timo Sirainen case HTTP_CLIENT_PEER_ADDR_HTTP:
b07a3abc4cc692661f5afd2fb654acb687884613Timo Sirainen conn_type = "HTTP";
b07a3abc4cc692661f5afd2fb654acb687884613Timo Sirainen break;
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen case HTTP_CLIENT_PEER_ADDR_HTTPS:
214aff73cd9809446bef169b216d6eb5a81079d8Timo Sirainen conn_type = "HTTPS";
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen break;
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL:
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen conn_type = "Tunneled HTTPS";
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen break;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen case HTTP_CLIENT_PEER_ADDR_RAW:
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn_type = "Raw";
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen break;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen case HTTP_CLIENT_PEER_ADDR_UNIX:
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn_type = "Unix";
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen break;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen }
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn = i_new(struct http_client_connection, 1);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn->refcount = 1;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn->client = peer->client;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn->id = id++;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn->peer = peer;
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen if (peer->addr.type != HTTP_CLIENT_PEER_ADDR_RAW)
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen i_array_init(&conn->request_wait_list, 16);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen conn->label = i_strdup_printf("%s [%d]",
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen http_client_peer_label(peer), conn->id);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen switch (peer->addr.type) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL:
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_connect_tunnel
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (conn, &addr->a.tcp.ip, addr->a.tcp.port);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen break;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen case HTTP_CLIENT_PEER_ADDR_UNIX:
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen connection_init_client_unix(peer->client->conn_list, &conn->conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen addr->a.un.path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->connect_initialized = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_connect(conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen break;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen default:
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen connection_init_client_ip(peer->client->conn_list, &conn->conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen &addr->a.tcp.ip, addr->a.tcp.port);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->connect_initialized = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_connect(conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_append(&peer->conns, &conn, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_debug(conn,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "%s connection created (%d parallel connections exist)%s",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn_type, array_count(&peer->conns),
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (conn->to_input == NULL ? "" : " [broken]"));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return conn;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid http_client_connection_ref(struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(conn->refcount > 0);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->refcount++;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenhttp_client_connection_disconnect(struct http_client_connection *conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_peer *peer = conn->peer;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ARRAY_TYPE(http_client_connection) *conn_arr;
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen struct http_client_connection *const *conn_idx;
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen if (conn->disconnected)
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen return;
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen conn->disconnected = TRUE;
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen http_client_connection_debug(conn, "Connection disconnect");
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->closing = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->connected = FALSE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->connect_request != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_request_abort(&conn->connect_request);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->incoming_payload != NULL) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* the stream is still accessed by lib-http caller. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_stream_remove_destroy_callback(conn->incoming_payload,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_payload_destroyed);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->incoming_payload = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_connection_abort_any_requests(conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->http_parser != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_response_parser_deinit(&conn->http_parser);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->connect_initialized)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen connection_disconnect(&conn->conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->io_req_payload != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen io_remove(&conn->io_req_payload);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->to_requests != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_remove(&conn->to_requests);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->to_connect != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_remove(&conn->to_connect);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->to_input != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_remove(&conn->to_input);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->to_idle != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_remove(&conn->to_idle);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->to_response != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen timeout_remove(&conn->to_response);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* remove this connection from the list */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn_arr = &peer->conns;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_foreach(conn_arr, conn_idx) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (*conn_idx == conn) {
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen array_delete(conn_arr, array_foreach_idx(conn_arr, conn_idx), 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen break;
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen }
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen }
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (conn->connect_succeeded)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen http_client_peer_connection_lost(peer);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
92a7f5f9bf20c0bd1b1ac309d100f9c144e2b127Timo Sirainenbool http_client_connection_unref(struct http_client_connection **_conn)
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *conn = *_conn;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(conn->refcount > 0);
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen *_conn = NULL;
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen if (--conn->refcount > 0)
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen return TRUE;
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen http_client_connection_debug(conn, "Connection destroy");
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen http_client_connection_disconnect(conn);
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen i_assert(conn->io_req_payload == NULL);
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen i_assert(conn->to_requests == NULL);
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen i_assert(conn->to_connect == NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(conn->to_input == NULL);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen i_assert(conn->to_idle == NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(conn->to_response == NULL);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen if (array_is_created(&conn->request_wait_list))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_free(&conn->request_wait_list);
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen if (conn->ssl_iostream != NULL)
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen ssl_iostream_unref(&conn->ssl_iostream);
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen if (conn->connect_initialized)
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen connection_deinit(&conn->conn);
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen i_free(conn->label);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_free(conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return FALSE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
ce74395e2a932342e04fb682395bcce111574969Timo Sirainenvoid http_client_connection_close(struct http_client_connection **_conn)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct http_client_connection *conn = *_conn;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen http_client_connection_debug(conn, "Connection close");
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen http_client_connection_disconnect(conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch http_client_connection_unref(_conn);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid http_client_connection_peer_closed(struct http_client_connection **_conn)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen{
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen struct http_client_connection *conn = *_conn;
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen http_client_connection_debug(conn, "Peer closed");
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen http_client_connection_disconnect(conn);
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if (http_client_connection_unref(_conn))
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen conn->peer = NULL;
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen}
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainenvoid http_client_connection_switch_ioloop(struct http_client_connection *conn)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen{
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if (conn->io_req_payload != NULL)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen conn->io_req_payload = io_loop_move_io(&conn->io_req_payload);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if (conn->to_requests != NULL)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen conn->to_requests = io_loop_move_timeout(&conn->to_requests);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if (conn->to_connect != NULL)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen conn->to_connect = io_loop_move_timeout(&conn->to_connect);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if (conn->to_input != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen conn->to_input = io_loop_move_timeout(&conn->to_input);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if (conn->to_idle != NULL)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen conn->to_idle = io_loop_move_timeout(&conn->to_idle);
b6c9cc2bf7517adcc0b9f98696c61bde321900f6Timo Sirainen if (conn->to_response != NULL)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen conn->to_response = io_loop_move_timeout(&conn->to_response);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen if (conn->incoming_payload != NULL)
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen i_stream_switch_ioloop(conn->incoming_payload);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen connection_switch_ioloop(&conn->conn);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen}
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen