http-client.c revision ff8a751fb9227a4fd73b2cdaa16d7a2616b3e7e7
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "lib.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "net.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "str.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "hash.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "array.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "ioloop.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "istream.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "ostream.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "connection.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "dns-lookup.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "iostream-rawlog.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "iostream-ssl.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "http-url.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "http-client-private.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#define HTTP_DEFAULT_PORT 80
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#define HTTPS_DEFAULT_PORT 443
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch/* Structure:
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch http_client_context:
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch Shared context between multiple independent HTTP clients. This allows host
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch name lookup data, peer status and idle connections to be shared between
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch clients.
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch http_client:
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
d67f004ebf944adca3ba09ed547febfa75442476Stephan Bosch Acts much like a browser; it is not dedicated to a single host. Client can
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch accept requests to different hosts, which can be served at different IPs.
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch Redirects are handled in the background by making a new connection.
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch Connections to new hosts are created once needed for servicing a request.
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch http_client_request:
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
d67f004ebf944adca3ba09ed547febfa75442476Stephan Bosch The request semantics are similar to imapc commands. Create a request,
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch optionally modify some aspects of it, and finally submit it. Once finished,
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch a callback is called with the returned response.
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch http_client_host_shared:
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch We maintain a 'cache' of hosts for which we have looked up IPs. This cache
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch is maintained in client context, so multiple clients can share it. One host
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch can have multiple IPs.
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch http_client_host:
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch A host object maintains client-specific information for a host. The queues
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch that the client has for this host are listed here. For one host, there is a
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch separate queue for each used server port.
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch http_client_queue:
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch Requests are queued in a queue object. These queues are maintained for each
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch host:port target and listed in the host object. The queue object is
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch responsible for starting connection attempts to TCP port at the various IPs
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch known for the host.
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch http_client_peer_pool:
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch A peer pool lists all unused and pending connections to a peer, grouped by
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch a compatible configuration, e.g. in terms of SSL and rawlog. Once needed,
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch peers can claim/request an existing/new connection from the pool.
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch http_client_peer_shared:
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch The shared peer object records state information about a peer, which is a
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch service access point (ip:port or unix socket path). The peer object also
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch maintains lists of idle and pending connections to this service, which are
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch grouped in pools with compatible client configuration. Each client has a
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch separate (non-shared) peer object for client-specific state information.
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch http_client_peer:
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch A peer object maintains client-specific information for a peer. Claimed
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch connections are dedicated to one peer (and therefore one client).
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch http-client-connection:
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch This is an actual connection to a server. Once a connection is ready to
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch handle requests, it claims a request from a queue object. One connection can
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch service multiple hosts and one host can have multiple associated connections,
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch possibly to different ips and ports.
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainenstatic struct http_client_context *http_client_global_context = NULL;
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch/*
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch * Client
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Boschstruct http_client *
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Boschhttp_client_init_shared(struct http_client_context *cctx,
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch const struct http_client_settings *set)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
fd30e54bd56f0869f5c2e14b42fd53f7b36cff45Stephan Bosch static unsigned int id = 0;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client *client;
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen const char *log_prefix;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool_t pool;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool = pool_alloconly_create("http client", 1024);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch client = p_new(pool, struct http_client, 1);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch client->pool = pool;
c275cef636c79e1d08b3a82462c4abdca6f8cef3Martti Rannanjärvi
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch /* create private context if none is provided */
fd30e54bd56f0869f5c2e14b42fd53f7b36cff45Stephan Bosch id++;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (cctx != NULL) {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->cctx = cctx;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch http_client_context_ref(cctx);
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen log_prefix = t_strdup_printf("http-client[%u]: ", id);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch } else {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->cctx = cctx = http_client_context_create(set);
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen log_prefix = "http-client: ";
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch }
c275cef636c79e1d08b3a82462c4abdca6f8cef3Martti Rannanjärvi
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen struct event *parent_event;
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen if (set != NULL && set->event != NULL)
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen parent_event = set->event;
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen else if (cctx->event == NULL)
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen parent_event = NULL;
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen else {
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen /* FIXME: we could use cctx->event, but it already has a log
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen prefix that we don't want.. should we update event API to
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen support replacing parent's log prefix? */
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen parent_event = event_get_parent(cctx->event);
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen }
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen client->event = event_create(parent_event);
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen if ((set != NULL && set->debug) || (cctx != NULL && cctx->set.debug))
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen event_set_forced_debug(client->event, TRUE);
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen event_set_append_log_prefix(client->event, log_prefix);
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch /* merge provided settings with context defaults */
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set = cctx->set;
ea4a85f5883baa653e8e60246c6ad570565cd831Stephan Bosch if (set != NULL) {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->user_agent != NULL && *set->user_agent != '\0')
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.user_agent = p_strdup_empty(pool, set->user_agent);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->rawlog_dir != NULL && *set->rawlog_dir != '\0')
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.rawlog_dir = p_strdup_empty(pool, set->rawlog_dir);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->ssl != NULL)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.ssl = ssl_iostream_settings_dup(pool, set->ssl);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->proxy_socket_path != NULL && *set->proxy_socket_path != '\0') {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.proxy_socket_path = p_strdup(pool, set->proxy_socket_path);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.proxy_url = NULL;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch } else if (set->proxy_url != NULL) {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.proxy_url = http_url_clone(pool, set->proxy_url);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.proxy_socket_path = NULL;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch }
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->proxy_username != NULL && *set->proxy_username != '\0') {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.proxy_username = p_strdup_empty(pool, set->proxy_username);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.proxy_password = p_strdup(pool, set->proxy_password);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch } else if (set->proxy_url != NULL && set->proxy_url->user != NULL &&
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch *set->proxy_url->user != '\0') {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.proxy_username =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch p_strdup_empty(pool, set->proxy_url->user);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.proxy_password =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch p_strdup(pool, set->proxy_url->password);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch }
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->max_parallel_connections > 0)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.max_parallel_connections = set->max_parallel_connections;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->max_pipelined_requests > 0)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.max_pipelined_requests = set->max_pipelined_requests;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->max_attempts > 0)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.max_attempts = set->max_attempts;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->max_connect_attempts > 0)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.max_connect_attempts = set->max_connect_attempts;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->connect_backoff_time_msecs > 0) {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.connect_backoff_time_msecs =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch set->connect_backoff_time_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch }
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->connect_backoff_max_time_msecs > 0) {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.connect_backoff_max_time_msecs =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch set->connect_backoff_max_time_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch }
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.no_auto_redirect =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.no_auto_redirect || set->no_auto_redirect;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.no_auto_retry =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.no_auto_retry || set->no_auto_retry;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.no_ssl_tunnel =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.no_ssl_tunnel || set->no_ssl_tunnel;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->max_redirects > 0)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.max_redirects = set->max_redirects;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->request_absolute_timeout_msecs > 0) {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.request_absolute_timeout_msecs =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch set->request_absolute_timeout_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch }
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->request_timeout_msecs > 0)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.request_timeout_msecs = set->request_timeout_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->connect_timeout_msecs > 0)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.connect_timeout_msecs = set->connect_timeout_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->soft_connect_timeout_msecs > 0)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.soft_connect_timeout_msecs = set->soft_connect_timeout_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->max_auto_retry_delay > 0)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.max_auto_retry_delay = set->max_auto_retry_delay;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch client->set.debug = client->set.debug || set->debug;
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch }
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch i_array_init(&client->delayed_failing_requests, 1);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return client;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Boschstruct http_client *
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Boschhttp_client_init(const struct http_client_settings *set)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch{
e7bc4ce82122c30696e60789432ffeb2e26b265bTimo Sirainen return http_client_init_shared(http_client_get_global_context(), set);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch}
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
ff8a751fb9227a4fd73b2cdaa16d7a2616b3e7e7Timo Sirainenstruct http_client *
ff8a751fb9227a4fd73b2cdaa16d7a2616b3e7e7Timo Sirainenhttp_client_init_private(const struct http_client_settings *set)
ff8a751fb9227a4fd73b2cdaa16d7a2616b3e7e7Timo Sirainen{
ff8a751fb9227a4fd73b2cdaa16d7a2616b3e7e7Timo Sirainen return http_client_init_shared(NULL, set);
ff8a751fb9227a4fd73b2cdaa16d7a2616b3e7e7Timo Sirainen}
ff8a751fb9227a4fd73b2cdaa16d7a2616b3e7e7Timo Sirainen
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_deinit(struct http_client **_client)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client *client = *_client;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch struct http_client_request *req;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_host *host;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_peer *peer;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
f9d2a1f21ad65262bc630f0834d7eead06a1bac3Timo Sirainen *_client = NULL;
f9d2a1f21ad65262bc630f0834d7eead06a1bac3Timo Sirainen
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch /* destroy requests without calling callbacks */
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch req = client->requests_list;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch while (req != NULL) {
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch struct http_client_request *next_req = req->next;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch http_client_request_destroy(&req);
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch req = next_req;
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch }
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch i_assert(client->requests_count == 0);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* free peers */
9dc01e0d10a61cab14867b26bf0d2d1dcf8ad978Timo Sirainen while (client->peers_list != NULL) {
9dc01e0d10a61cab14867b26bf0d2d1dcf8ad978Timo Sirainen peer = client->peers_list;
ebe0f5e387744621b73c4db79d5891ccbe0a1321Stephan Bosch http_client_peer_close(&peer);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* free hosts */
aacf2a69acc59e9382578d6f4e030788abc79706Timo Sirainen while (client->hosts_list != NULL) {
aacf2a69acc59e9382578d6f4e030788abc79706Timo Sirainen host = client->hosts_list;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_host_free(&host);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch array_free(&client->delayed_failing_requests);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_failing_requests);
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen if (client->ssl_ctx != NULL)
15d19d6e4daf460d8d2c82b981e23996dbdf7ba5Timo Sirainen ssl_iostream_context_unref(&client->ssl_ctx);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch http_client_context_unref(&client->cctx);
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen event_unref(&client->event);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool_unref(&client->pool);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Boschstruct ioloop *http_client_switch_ioloop(struct http_client *client)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch struct ioloop *prev_ioloop = client->ioloop;
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch struct http_client_peer *peer;
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch struct http_client_host *host;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch /* move peers */
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch for (peer = client->peers_list; peer != NULL;
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch peer = peer->client_next)
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch http_client_peer_switch_ioloop(peer);
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch /* move hosts/queues */
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch for (host = client->hosts_list; host != NULL;
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch host = host->client_next)
636d0f43138468f8efe685a681326b123f660e49Timo Sirainen http_client_host_switch_ioloop(host);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch /* move timeouts */
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch if (client->to_failing_requests != NULL) {
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch client->to_failing_requests =
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch io_loop_move_timeout(&client->to_failing_requests);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch }
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch http_client_context_switch_ioloop(client->cctx);
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch client->ioloop = current_ioloop;
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch return prev_ioloop;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_wait(struct http_client *client)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch struct ioloop *prev_ioloop, *client_ioloop, *prev_client_ioloop;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
a991cfe2157e58ee43bc580f517ce9ef0dfb7acfStephan Bosch if (client->requests_count == 0)
fb1be3de0159d6a10e916ad992e2bc53be64c6d5Timo Sirainen return;
fb1be3de0159d6a10e916ad992e2bc53be64c6d5Timo Sirainen
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch prev_ioloop = current_ioloop;
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch client_ioloop = io_loop_create();
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch prev_client_ioloop = http_client_switch_ioloop(client);
856ae2ad98cee79b2719911a3cc131d7f4ec8a90Timo Sirainen if (client->set.dns_client != NULL)
856ae2ad98cee79b2719911a3cc131d7f4ec8a90Timo Sirainen dns_client_switch_ioloop(client->set.dns_client);
1a9a35a6b307f8d5b25345af55e40a99162b4072Timo Sirainen /* either we're waiting for network I/O or we're getting out of a
1a9a35a6b307f8d5b25345af55e40a99162b4072Timo Sirainen callback using timeout_add_short(0) */
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch i_assert(io_loop_have_ios(client_ioloop) ||
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch io_loop_have_immediate_timeouts(client_ioloop));
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch client->waiting = TRUE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch do {
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(client->event,
a991cfe2157e58ee43bc580f517ce9ef0dfb7acfStephan Bosch "Waiting for %d requests to finish", client->requests_count);
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch io_loop_run(client_ioloop);
a991cfe2157e58ee43bc580f517ce9ef0dfb7acfStephan Bosch } while (client->requests_count > 0);
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch client->waiting = FALSE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(client->event, "All requests finished");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch if (prev_client_ioloop != NULL)
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch io_loop_set_current(prev_client_ioloop);
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch else
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch io_loop_set_current(prev_ioloop);
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch (void)http_client_switch_ioloop(client);
856ae2ad98cee79b2719911a3cc131d7f4ec8a90Timo Sirainen if (client->set.dns_client != NULL)
856ae2ad98cee79b2719911a3cc131d7f4ec8a90Timo Sirainen dns_client_switch_ioloop(client->set.dns_client);
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch io_loop_set_current(client_ioloop);
e8a1b62fe4a81b211dcccd1a58b44f254074eab6Stephan Bosch io_loop_destroy(&client_ioloop);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
17cd0e0963f2fb0e66d49703e8cd0bda1b842468Timo Sirainenunsigned int http_client_get_pending_request_count(struct http_client *client)
17cd0e0963f2fb0e66d49703e8cd0bda1b842468Timo Sirainen{
a991cfe2157e58ee43bc580f517ce9ef0dfb7acfStephan Bosch return client->requests_count;
17cd0e0963f2fb0e66d49703e8cd0bda1b842468Timo Sirainen}
17cd0e0963f2fb0e66d49703e8cd0bda1b842468Timo Sirainen
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainenint http_client_init_ssl_ctx(struct http_client *client, const char **error_r)
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen{
ba1c847d0af4afe4787ed470d0c818e948e184e2Timo Sirainen const char *error;
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen if (client->ssl_ctx != NULL)
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen return 0;
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen
5d31e4b38ef03b002e2ab245a7f8a4c0da3dd03dTimo Sirainen if (client->set.ssl == NULL) {
5d31e4b38ef03b002e2ab245a7f8a4c0da3dd03dTimo Sirainen *error_r = "Requested https connection, but no SSL settings given";
5d31e4b38ef03b002e2ab245a7f8a4c0da3dd03dTimo Sirainen return -1;
5d31e4b38ef03b002e2ab245a7f8a4c0da3dd03dTimo Sirainen }
ebcf7d6c9222f2c96053516e0c90994bff62dd55Timo Sirainen if (ssl_iostream_client_context_cache_get(client->set.ssl, &client->ssl_ctx, &error) < 0) {
ba1c847d0af4afe4787ed470d0c818e948e184e2Timo Sirainen *error_r = t_strdup_printf("Couldn't initialize SSL context: %s",
ba1c847d0af4afe4787ed470d0c818e948e184e2Timo Sirainen error);
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen return -1;
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen }
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen return 0;
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen}
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch/*
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch * Delayed request errors
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch */
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch
fca68889b287d8eed4babe72a231bd6079da012dStephan Boschstatic void
fca68889b287d8eed4babe72a231bd6079da012dStephan Boschhttp_client_handle_request_errors(struct http_client *client)
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch{
8d845733408c0cb06a8884d12101beb0d40e6869Stephan Bosch struct http_client_request *const *req_idx;
8d845733408c0cb06a8884d12101beb0d40e6869Stephan Bosch
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch timeout_remove(&client->to_failing_requests);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch
8d845733408c0cb06a8884d12101beb0d40e6869Stephan Bosch array_foreach(&client->delayed_failing_requests, req_idx) {
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch struct http_client_request *req = *req_idx;
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch i_assert(req->refcount == 1);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch http_client_request_error_delayed(&req);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch }
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch array_clear(&client->delayed_failing_requests);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch}
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch
fca68889b287d8eed4babe72a231bd6079da012dStephan Boschvoid http_client_delay_request_error(struct http_client *client,
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch struct http_client_request *req)
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch{
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch if (client->to_failing_requests == NULL) {
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch client->to_failing_requests = timeout_add_short(0,
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch http_client_handle_request_errors, client);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch }
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch array_append(&client->delayed_failing_requests, &req, 1);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch}
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch
fca68889b287d8eed4babe72a231bd6079da012dStephan Boschvoid http_client_remove_request_error(struct http_client *client,
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch struct http_client_request *req)
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch{
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch struct http_client_request *const *reqs;
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch unsigned int i, count;
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch reqs = array_get(&client->delayed_failing_requests, &count);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch for (i = 0; i < count; i++) {
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch if (reqs[i] == req) {
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch array_delete(&client->delayed_failing_requests, i, 1);
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch return;
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch }
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch }
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch}
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch/*
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch * Client shared context
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch */
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Boschstruct http_client_context *
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Boschhttp_client_context_create(const struct http_client_settings *set)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch{
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch struct http_client_context *cctx;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch pool_t pool;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch pool = pool_alloconly_create("http client context", 1024);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx = p_new(pool, struct http_client_context, 1);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->pool = pool;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->refcount = 1;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen cctx->event = event_create(set->event);
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen if (set->debug)
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen event_set_forced_debug(cctx->event, TRUE);
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen event_set_append_log_prefix(cctx->event, "http-client: ");
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.dns_client = set->dns_client;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.dns_client_socket_path =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch p_strdup_empty(pool, set->dns_client_socket_path);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.dns_ttl_msecs = (set->dns_ttl_msecs == 0 ?
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch HTTP_CLIENT_DEFAULT_DNS_TTL_MSECS : set->dns_ttl_msecs);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.user_agent = p_strdup_empty(pool, set->user_agent);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.rawlog_dir = p_strdup_empty(pool, set->rawlog_dir);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->ssl != NULL)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.ssl = ssl_iostream_settings_dup(pool, set->ssl);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->proxy_socket_path != NULL && *set->proxy_socket_path != '\0') {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.proxy_socket_path = p_strdup(pool, set->proxy_socket_path);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch } else if (set->proxy_url != NULL) {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.proxy_url = http_url_clone(pool, set->proxy_url);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch }
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (set->proxy_username != NULL && *set->proxy_username != '\0') {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.proxy_username = p_strdup_empty(pool, set->proxy_username);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.proxy_password = p_strdup(pool, set->proxy_password);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch } else if (set->proxy_url != NULL) {
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.proxy_username =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch p_strdup_empty(pool, set->proxy_url->user);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.proxy_password =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch p_strdup(pool, set->proxy_url->password);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch }
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.max_idle_time_msecs = set->max_idle_time_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.max_pipelined_requests =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch (set->max_pipelined_requests > 0 ? set->max_pipelined_requests : 1);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.max_parallel_connections =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch (set->max_parallel_connections > 0 ? set->max_parallel_connections : 1);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.max_attempts = set->max_attempts;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.max_connect_attempts = set->max_connect_attempts;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.connect_backoff_time_msecs =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch set->connect_backoff_time_msecs == 0 ?
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch HTTP_CLIENT_DEFAULT_BACKOFF_TIME_MSECS :
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch set->connect_backoff_time_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.connect_backoff_max_time_msecs =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch set->connect_backoff_max_time_msecs == 0 ?
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch HTTP_CLIENT_DEFAULT_BACKOFF_MAX_TIME_MSECS :
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch set->connect_backoff_max_time_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.no_auto_redirect = set->no_auto_redirect;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.no_auto_retry = set->no_auto_retry;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.no_ssl_tunnel = set->no_ssl_tunnel;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.max_redirects = set->max_redirects;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.response_hdr_limits = set->response_hdr_limits;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.request_absolute_timeout_msecs =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch set->request_absolute_timeout_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.request_timeout_msecs =
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch set->request_timeout_msecs == 0 ?
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch HTTP_CLIENT_DEFAULT_REQUEST_TIMEOUT_MSECS :
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch set->request_timeout_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.connect_timeout_msecs = set->connect_timeout_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.soft_connect_timeout_msecs = set->soft_connect_timeout_msecs;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.max_auto_retry_delay = set->max_auto_retry_delay;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.socket_send_buffer_size = set->socket_send_buffer_size;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.socket_recv_buffer_size = set->socket_recv_buffer_size;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->set.debug = set->debug;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch cctx->conn_list = http_client_connection_list_init();
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch hash_table_create(&cctx->hosts, default_pool, 0, str_hash, strcmp);
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch hash_table_create(&cctx->peers, default_pool, 0,
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch http_client_peer_addr_hash, http_client_peer_addr_cmp);
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch return cctx;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch}
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Boschvoid http_client_context_ref(struct http_client_context *cctx)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch{
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch cctx->refcount++;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch}
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Boschvoid http_client_context_unref(struct http_client_context **_cctx)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch{
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch struct http_client_context *cctx = *_cctx;
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch struct http_client_peer_shared *peer;
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch struct http_client_host_shared *hshared;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch *_cctx = NULL;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch i_assert(cctx->refcount > 0);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch if (--cctx->refcount > 0)
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch return;
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch /* free hosts */
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch while (cctx->hosts_list != NULL) {
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch hshared = cctx->hosts_list;
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch http_client_host_shared_free(&hshared);
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch }
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch hash_table_destroy(&cctx->hosts);
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch /* close all idle connections */
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch while (cctx->peers_list != NULL) {
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch peer = cctx->peers_list;
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch http_client_peer_shared_close(&peer);
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch i_assert(peer == NULL);
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch }
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch hash_table_destroy(&cctx->peers);
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch connection_list_deinit(&cctx->conn_list);
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen event_unref(&cctx->event);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch pool_unref(&cctx->pool);
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch}
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch
9fe6a55877bee691b32c12c7be56242054841670Stephan Boschvoid http_client_context_switch_ioloop(struct http_client_context *cctx)
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch{
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch struct connection *_conn = cctx->conn_list->connections;
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch struct http_client_host_shared *hshared;
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch /* move connections */
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch /* FIXME: we wouldn't necessarily need to switch all of them
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch immediately, only those that have requests now. but also connections
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch that get new requests before ioloop is switched again.. */
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch for (; _conn != NULL; _conn = _conn->next) {
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch struct http_client_connection *conn =
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch (struct http_client_connection *)_conn;
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch http_client_connection_switch_ioloop(conn);
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch }
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch /* move dns lookups and delayed requests */
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch for (hshared = cctx->hosts_list; hshared != NULL;
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch hshared = hshared->next)
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch http_client_host_shared_switch_ioloop(hshared);
9fe6a55877bee691b32c12c7be56242054841670Stephan Bosch}
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainenstatic void http_client_global_context_free(void)
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen{
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen http_client_context_unref(&http_client_global_context);
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen}
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainenstruct http_client_context *http_client_get_global_context(void)
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen{
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen if (http_client_global_context != NULL)
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen return http_client_global_context;
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen struct http_client_settings set;
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen i_zero(&set);
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen http_client_global_context = http_client_context_create(&set);
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen /* keep this a bit higher than lib-ssl-iostream */
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen lib_atexit_priority(http_client_global_context_free, LIB_ATEXIT_PRIORITY_LOW-1);
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen return http_client_global_context;
788e61d347adbdb7c9a4d767e381f4bd8a3526b2Timo Sirainen}