http-client.c revision 9fe6a55877bee691b32c12c7be56242054841670
/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "net.h"
#include "str.h"
#include "hash.h"
#include "array.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "connection.h"
#include "dns-lookup.h"
#include "iostream-rawlog.h"
#include "iostream-ssl.h"
#include "http-url.h"
#include "http-client-private.h"
#define HTTP_DEFAULT_PORT 80
#define HTTPS_DEFAULT_PORT 443
/* Structure:
http-client:
Acts much like a browser; it is not dedicated to a single host. Client can
accept requests to different hosts, which can be served at different IPs.
Redirects are handled in the background by making a new connection.
Connections to new hosts are created once needed for servicing a request.
http-client-request:
The request semantics are similar to imapc commands. Create a request,
optionally modify some aspects of it and finally submit it. Once finished,
a callback is called with the returned response.
http-client-host:
We maintain a 'cache' of hosts for which we have looked up IPs. One host
can have multiple IPs.
http-client-queue:
Requests are queued in a queue object. These queues are maintained for each
host:port target and listed in the host object. The queue object is
responsible for starting connection attempts to TCP port at the various IPs
known for the host.
http-client-peer:
(== peer_addr).
http-client-connection:
This is an actual connection to a server. Once a connection is ready to
handle requests, it claims a request from a queue object. One connection can
service multiple hosts and one host can have multiple associated connections,
possibly to different ips and ports.
*/
/*
* Logging
*/
static inline void
static inline void
const char *format, ...)
{
}
/*
* Client
*/
struct http_client *
const struct http_client_settings *set)
{
struct http_client *client;
/* create private context if none is provided */
} else {
}
/* merge provided settings with context defaults */
}
if (set->dns_ttl_msecs > 0)
}
}
if (set->max_idle_time_msecs > 0)
if (set->max_parallel_connections > 0)
if (set->max_pipelined_requests > 0)
if (set->max_attempts > 0)
if (set->max_connect_attempts > 0)
if (set->connect_backoff_time_msecs > 0) {
}
if (set->connect_backoff_max_time_msecs > 0) {
}
if (set->max_redirects > 0)
if (set->request_absolute_timeout_msecs > 0) {
}
if (set->request_timeout_msecs > 0)
if (set->connect_timeout_msecs > 0)
if (set->soft_connect_timeout_msecs > 0)
if (set->max_auto_retry_delay > 0)
}
return client;
}
struct http_client *
{
}
{
struct http_client_request *req;
struct http_client_host *host;
struct http_client_peer *peer;
/* destroy requests without calling callbacks */
}
/* free peers */
}
/* free hosts */
}
}
{
struct http_client_host *host;
struct http_client_peer *peer;
/* move peers */
/* move dns lookups and delayed requests */
/* move timeouts */
}
}
{
if (client->requests_count == 0)
return;
/* either we're waiting for network I/O or we're getting out of a
callback using timeout_add_short(0) */
do {
} while (client->requests_count > 0);
}
{
return client->requests_count;
}
{
const char *error;
return 0;
*error_r = "Requested https connection, but no SSL settings given";
return -1;
}
error);
return -1;
}
return 0;
}
/*
* Delayed request errors
*/
static void
{
struct http_client_request *const *req_idx;
}
}
struct http_client_request *req)
{
}
}
struct http_client_request *req)
{
struct http_client_request *const *reqs;
unsigned int i, count;
for (i = 0; i < count; i++) {
return;
}
}
}
/*
* Client shared context
*/
struct http_client_context *
{
struct http_client_context *cctx;
}
}
set->connect_backoff_time_msecs == 0 ?
set->connect_backoff_max_time_msecs == 0 ?
set->request_timeout_msecs == 0 ?
return cctx;
}
{
}
{
return;
}
{
/* move connections */
/* FIXME: we wouldn't necessarily need to switch all of them
immediately, only those that have requests now. but also connections
that get new requests before ioloop is switched again.. */
struct http_client_connection *conn =
(struct http_client_connection *)_conn;
}
}